重载模板函数推导错误
Overloaded template functions deduction error
我很难做到这一点。我想创建重载模板函数地狱,使此类调用成为可能和正确 (GMock):
ASSERT_EQ(min(1, 2), 1);
ASSERT_EQ(min(std::less<>(),3,2), 2);
auto abs_comp = [](auto el1, auto el2){
return std::abs(el1) < std::abs(el2);
};
ASSERT_EQ(min(abs_comp, -1, -5), -1);
ASSERT_EQ(min(4, 3, 2, 1), 1);
一切都很好,除了这个断言:
ASSERT_EQ(min(std::less<>(), 3,2,1), 2);
当我提取函数本身时得到一个有意义的错误:
min(std::less<>(), 3,2,1)
我明白了:
In file included from /home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/container_minimum_test.cpp:4:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h: In instantiation of ‘First cppchallenge::lang::min(First, Args ...) [with First = int; Args = {}; <template-parameter-1-3> = std::enable_if<true, void>]’:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: required from ‘First cppchallenge::lang::min(First, Args ...) [with First = std::less<void>; Args = {int}; <template-parameter-1-3> = std::enable_if<false, void>]’
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:19: required from ‘First cppchallenge::lang::min(First, Args ...) [with First = std::less<void>; Args = {int, int, int}; <template-parameter-1-3> = std::enable_if<false, void>]’
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/container_minimum_test.cpp:40:33: required from here
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: error: no matching function for call to ‘min()’
return min(first, min(args...));
~~~^~~~~~~~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:8:7: note: candidate: ‘template<class T> T cppchallenge::lang::min(T, T)’
T min(T first, T second) {
^~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:8:7: note: template argument deduction/substitution failed:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: note: candidate expects 2 arguments, 0 provided
return min(first, min(args...));
~~~^~~~~~~~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:16:11: note: candidate: ‘template<class First, class ... Args, class> First cppchallenge::lang::min(First, Args ...)’
First min(First first, Args... args) {
^~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:16:11: note: template argument deduction/substitution failed:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: note: candidate expects at least 1 argument, 0 provided
return min(first, min(args...));
~~~^~~~~~~~~
gmake[3]: *** [CMakeFiles/ModernCppChallengeLang.dir/build.make:102: CMakeFiles/ModernCppChallengeLang.dir/tst/lang/container_minimum_test.cpp.o] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:116: CMakeFiles/ModernCppChallengeLang.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:128: CMakeFiles/ModernCppChallengeLang.dir/rule] Error 2
gmake: *** [Makefile:177: ModernCppChallengeLang] Error 2
模板函数如下:
namespace cppchallenge::lang {
//#1
template<typename T>
T min(T first, T second) {
return first < second ? first : second;
}
template<typename First, typename... Args>
using are_same = std::conjunction<std::is_same<First, Args>...>;
//#2
template<typename First, typename... Args, typename = std::enable_if<are_same<First, Args...>::value, void>>
First min(First first, Args... args) {
return min(first, min(args...));
}
//#3
template<typename Comparator, typename T>
T min(Comparator comp, T first, T second) {
return comp(first, second) ? first : second;
}
//#4
template<typename Comparator, typename First, typename... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>,
typename std::enable_if<std::is_convertible<Comparator, std::function<bool(First,First)>>::value>::type>
First min(Comparator comp, First first, Args... args) {
return min(comp, first, min(comp, args...));
}
}
错误指向函数 #2,尽管它应该使用 #4。
我想错误出在以下模板函数中:您必须在最后一个 ::type
之后添加一些内容作为 * = nullptr
template<typename Comparator, typename First, typename... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>,
typename std::enable_if<std::is_convertible<Comparator, std::function<bool(First,First)>>::value>::type * = nullptr> // add * = nullptr
First min(Comparator comp, First first, Args... args) {
return comp(comp, first, min(comp, args...));
}
或者在最后一个 typename std::enable_if
之前添加一个 typename =
。
否则,如果一切顺利(如果 Firts
和所有 Args...
相等并且如果 Comparable
可转换为所需的 st::function
,则模板签名变为
template <typename Comparator, typename First, typename ... Args,
typename = std::enable_if<are_same<First, Args...>::value,
void>
和最后一个void
,单看是没有意义的(而且前面的std::enable_if
也没什么用;但这是另一个问题;见下面的"bonus suggestion" )
你应该转换成类似于
的东西
template <typename Comparator, typename First, typename ... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>
void * = nullptr>
//............^^^^^^^^^^^^
或
template <typename Comparator, typename First, typename ... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>,
typename = void>
//........^^^^^^^^^^^
额外建议:前面的 SFINAE 测试应该是
typename = std::enable_if_t<are_same<First, Args...>::value, void>
// ......................^^
或者(最后一个std::enable_if_t
参数默认为void
)
typename = std::enable_if_t<are_same<First, Args...>::value>
否则测试永远不会起作用并且该功能永远启用(从 First
和 Args...
类型的角度来看)。
SFINAE 测试中的类似问题
First min(First first, Args... args)
我很难做到这一点。我想创建重载模板函数地狱,使此类调用成为可能和正确 (GMock):
ASSERT_EQ(min(1, 2), 1);
ASSERT_EQ(min(std::less<>(),3,2), 2);
auto abs_comp = [](auto el1, auto el2){
return std::abs(el1) < std::abs(el2);
};
ASSERT_EQ(min(abs_comp, -1, -5), -1);
ASSERT_EQ(min(4, 3, 2, 1), 1);
一切都很好,除了这个断言:
ASSERT_EQ(min(std::less<>(), 3,2,1), 2);
当我提取函数本身时得到一个有意义的错误:
min(std::less<>(), 3,2,1)
我明白了:
In file included from /home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/container_minimum_test.cpp:4:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h: In instantiation of ‘First cppchallenge::lang::min(First, Args ...) [with First = int; Args = {}; <template-parameter-1-3> = std::enable_if<true, void>]’:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: required from ‘First cppchallenge::lang::min(First, Args ...) [with First = std::less<void>; Args = {int}; <template-parameter-1-3> = std::enable_if<false, void>]’
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:19: required from ‘First cppchallenge::lang::min(First, Args ...) [with First = std::less<void>; Args = {int, int, int}; <template-parameter-1-3> = std::enable_if<false, void>]’
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/container_minimum_test.cpp:40:33: required from here
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: error: no matching function for call to ‘min()’
return min(first, min(args...));
~~~^~~~~~~~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:8:7: note: candidate: ‘template<class T> T cppchallenge::lang::min(T, T)’
T min(T first, T second) {
^~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:8:7: note: template argument deduction/substitution failed:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: note: candidate expects 2 arguments, 0 provided
return min(first, min(args...));
~~~^~~~~~~~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:16:11: note: candidate: ‘template<class First, class ... Args, class> First cppchallenge::lang::min(First, Args ...)’
First min(First first, Args... args) {
^~~
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:16:11: note: template argument deduction/substitution failed:
/home/rumcajs/CLionProjects/ModernCppChallenge/tst/lang/../../src/lang/container_minimum.h:17:30: note: candidate expects at least 1 argument, 0 provided
return min(first, min(args...));
~~~^~~~~~~~~
gmake[3]: *** [CMakeFiles/ModernCppChallengeLang.dir/build.make:102: CMakeFiles/ModernCppChallengeLang.dir/tst/lang/container_minimum_test.cpp.o] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:116: CMakeFiles/ModernCppChallengeLang.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:128: CMakeFiles/ModernCppChallengeLang.dir/rule] Error 2
gmake: *** [Makefile:177: ModernCppChallengeLang] Error 2
模板函数如下:
namespace cppchallenge::lang {
//#1
template<typename T>
T min(T first, T second) {
return first < second ? first : second;
}
template<typename First, typename... Args>
using are_same = std::conjunction<std::is_same<First, Args>...>;
//#2
template<typename First, typename... Args, typename = std::enable_if<are_same<First, Args...>::value, void>>
First min(First first, Args... args) {
return min(first, min(args...));
}
//#3
template<typename Comparator, typename T>
T min(Comparator comp, T first, T second) {
return comp(first, second) ? first : second;
}
//#4
template<typename Comparator, typename First, typename... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>,
typename std::enable_if<std::is_convertible<Comparator, std::function<bool(First,First)>>::value>::type>
First min(Comparator comp, First first, Args... args) {
return min(comp, first, min(comp, args...));
}
}
错误指向函数 #2,尽管它应该使用 #4。
我想错误出在以下模板函数中:您必须在最后一个 ::type
* = nullptr
template<typename Comparator, typename First, typename... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>,
typename std::enable_if<std::is_convertible<Comparator, std::function<bool(First,First)>>::value>::type * = nullptr> // add * = nullptr
First min(Comparator comp, First first, Args... args) {
return comp(comp, first, min(comp, args...));
}
或者在最后一个 typename std::enable_if
之前添加一个 typename =
。
否则,如果一切顺利(如果 Firts
和所有 Args...
相等并且如果 Comparable
可转换为所需的 st::function
,则模板签名变为
template <typename Comparator, typename First, typename ... Args,
typename = std::enable_if<are_same<First, Args...>::value,
void>
和最后一个void
,单看是没有意义的(而且前面的std::enable_if
也没什么用;但这是另一个问题;见下面的"bonus suggestion" )
你应该转换成类似于
的东西template <typename Comparator, typename First, typename ... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>
void * = nullptr>
//............^^^^^^^^^^^^
或
template <typename Comparator, typename First, typename ... Args,
typename = std::enable_if<are_same<First, Args...>::value, void>,
typename = void>
//........^^^^^^^^^^^
额外建议:前面的 SFINAE 测试应该是
typename = std::enable_if_t<are_same<First, Args...>::value, void>
// ......................^^
或者(最后一个std::enable_if_t
参数默认为void
)
typename = std::enable_if_t<are_same<First, Args...>::value>
否则测试永远不会起作用并且该功能永远启用(从 First
和 Args...
类型的角度来看)。
First min(First first, Args... args)