use*_*080 6 c++ templates sfinae enable-if c++11
我尝试使用std::enable_if
未使用和未命名的类型参数,以免扭曲return
类型.但是,以下代码无法编译.
#include <iostream>
template <typename T, typename = std::enable_if_t<!std::is_integral<T>::value>>
T foo() { std::cout << "non-integral" << std::endl; return T(); }
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
T foo() { std::cout << "integral" << std::endl; return T(); }
int main() {
foo<float>();
foo<int>();
}
Run Code Online (Sandbox Code Playgroud)
编译器说:
7:3: error: redefinition of 'template<class T, class> T foo()'
4:3: note: 'template<class T, class> T foo()' previously declared here
In function 'int main()':
11:12: error: no matching function for call to 'foo()'
11:12: note: candidate is:
4:3: note: template<class T, class> T foo()
4:3: note: template argument deduction/substitution failed:
Run Code Online (Sandbox Code Playgroud)
这里有什么问题?我如何更改代码以使其编译?教科书"发现现代C++"明确鼓励使用std::enable_if
匿名类型参数.
编辑:我知道如果我std::enable_if
输入返回类型它是有效的.但是,我的目的是获得更多细节,如果我将它与匿名类型参数一起使用它不起作用.正如我所说,我的教科书鼓励使用匿名类型参数的变体,所以我想知道为什么我的代码不编译.
但是,我的目的是获得更多细节,如果我将它与匿名类型参数一起使用它不起作用.
默认值不参与重载决策,因此您实际上正在重新定义相同的功能.
让我们简化你的例子:
template<typename = int>
void f() {}
template<typename = void>
void f() {}
int main() {
f<>();
}
Run Code Online (Sandbox Code Playgroud)
上面的代码无法编译,因为它无法知道f
您要调用的版本.
在你的情况,如果我调用foo
的foo<void, void>
,我有几乎同样的问题.
编译器无法猜测我的意图是什么,以及第二个参数具有默认值的事实并不意味着您不能传递不同的类型.
因此,代码格式错误,编译器正确地给出了错误.
作为旁注,您仍然可以在不使用std::enable_if_t
返回类型的情况下使其工作.
举个例子:
#include <type_traits>
#include <iostream>
template <typename T, std::enable_if_t<!std::is_integral<T>::value>* = nullptr>
T foo() { std::cout << "non-integral" << std::endl; return T(); }
template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
T foo() { std::cout << "integral" << std::endl; return T(); }
int main() {
foo<float>();
foo<int>();
}
Run Code Online (Sandbox Code Playgroud)
虽然我试图弄清楚OP的(错误的)假设是什么并解释为什么会出现这种情况,但@TC正确地将注意力指向了对这个答案的评论中的实际原因.
值得引用他的评论,为答案添加更多细节:
这不是重载决议; 它的声明匹配.首先出现任何歧义都没有两个重载.这是两个重定义错误:函数模板和默认模板参数.
您可以输入enable_if
返回类型:
template <typename T>
std::enable_if_t<!std::is_integral<T>::value,T>
foo() { std::cout << "non-integral" << std::endl; return T(); }
template <typename T>
std::enable_if_t<std::is_integral<T>::value, T>
foo() { std::cout << "integral" << std::endl; return T(); }
Run Code Online (Sandbox Code Playgroud)
顺便说一句,enable_if_t
可从 C++14 获得,因此您可能想说typename std::enable_if<std::is_integral<T>::value, T>::type
。相当拗口。
但更惯用的(和可读的)是根据类型进行调度:
template <typename T>
T foo_impl(std::false_type) { std::cout << "non-integral" << std::endl; return T(); }
template <typename T>
T foo_impl(std::true_type) { std::cout << "integral" << std::endl; return T(); }
template <typename T>
T foo(){
return foo_impl<T>(typename std::is_integral<T>::type{});
}
Run Code Online (Sandbox Code Playgroud)