我有以下代码:
#include <iostream>
/*
template <class A, std::enable_if_t<!std::is_same_v<A, double>, bool> = true>
void test() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template <class A, std::enable_if_t<std::is_same_v<A, double>, bool> = true>
void test() {
std::cout << "SFINAE" << std::endl;
}
*/
template <class A, typename = std::enable_if_t<!std::is_same_v<A, double>>>
void test() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template <class A, typename = std::enable_if_t<std::is_same_v<A, double>>>
void test() {
std::cout << "SFINAE" << std::endl;
}
int main() {
test<int>();
test<double>();
}编译器抱怨
test_function_templ.cpp:21:6: error: redefinition of ‘template<class A, class> void test()’
21 | void test() {
| ^~~~
test_function_templ.cpp:16:6: note: ‘template<class A, class> void test()’ previously declared here
16 | void test() {
| ^~~~
test_function_templ.cpp: In function ‘int main()’:
test_function_templ.cpp:27:15: error: no matching function for call to ‘test<double>()’
27 | test<double>();
| ^
test_function_templ.cpp:16:6: note: candidate: ‘template<class A, class> void test()’
16 | void test() {
| ^~~~
test_function_templ.cpp:16:6: note: template argument deduction/substitution failed:
In file included from /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/move.h:57,
from /opt/rh/devtoolset-10/root/usr/include/c++/10/bits/nested_exception.h:40,
from /opt/rh/devtoolset-10/root/usr/include/c++/10/exception:148,
from /opt/rh/devtoolset-10/root/usr/include/c++/10/ios:39,
from /opt/rh/devtoolset-10/root/usr/include/c++/10/ostream:38,
from /opt/rh/devtoolset-10/root/usr/include/c++/10/iostream:39,
from test_function_templ.cpp:1:
/opt/rh/devtoolset-10/root/usr/include/c++/10/type_traits: In substitution of ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]’:
test_function_templ.cpp:15:20: required from here
/opt/rh/devtoolset-10/root/usr/include/c++/10/type_traits:2554:11: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
2554 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
| ^~~~~~~~~~~如果我使用第一组函数模板(代码中注释) test(),它将按预期的方式编译和运行。
问题
test<int>()将实例化test<int, void>(),调用test<double>()将实例化test<double, void>()。但是编译器似乎看到了两个重复的模板函数?发布于 2021-11-15 06:01:48
第一个代码段的问题被描述为这里 (参见/* WRONG */和/* RIGHT */代码片段分别映射到注释代码和未注释代码)。
一个常见的错误是声明两个仅在其默认模板参数中不同的函数模板。这不起作用,因为声明被视为相同函数模板的重声明(默认模板参数在功能模板等价中不考虑)。
这是我对为什么会这样的理解。
当编译器看到这个(正确的版本)
template <class A, std::enable_if_t<!std::is_same_v<A, double>, bool> = true>
void test() {}
template <class A, std::enable_if_t<std::is_same_v<A, double>, bool> = true>
void test() {}它不会看到重声明,因为它不知道两个std::enable_if_t是否会解析为相同的类型。如果它知道,那么它将是一个硬编译时错误,就像这是一个错误:
template <class A, bool = true>
void test() {}
template <class A, bool = false> // no matter the value; signature is the same
void test() {}这并不排除歧义可以发生在替换级别上。例如,原则上这些重载声明没有问题
template <class A, std::enable_if_t<std::is_convertible_v<A, double>, bool> = true>
void test() {}
template <class A, std::enable_if_t<std::is_convertible_v<A, int>, bool> = true>
void test() {}但是,一旦调用test<int>(),就会出现歧义,因为编译器将能够“成功”实例化每个重载,这都会导致template<int, bool = whatever>,这使得它们变得模糊。
至于错误的版本:
template <class A, typename = std::enable_if_t<!std::is_same_v<A, double>>>
void test() {}
template <class A, typename = std::enable_if_t<std::is_same_v<A, double>>>
void test() {}问题是,在查看如何使用它之前,编译器已经开始抱怨了,因为默认模板参数在函数模板等价中没有考虑。实际上,一个简单得多的例子显示了前面片段的问题:
template <class A, typename = typename A::foo>
void test() {}
template <class A, typename = typename A::bar>
void test() {}注意,与前面的片段完全一样,在最后一个片段中,每个重载本身都是正确的,直到您尝试将其与特定的A一起使用时,默认参数的表达式没有意义,从而导致了一个严重的错误。
但是,如果将这两个重载放在一起,就会产生歧义,因为默认的模板参数在函数模板等效中没有考虑。
https://stackoverflow.com/questions/69969960
复制相似问题