为什么"std::enable_if"需要默认值?
Why the default value is needed for `std::enable_if`?
为什么我必须在此std::enable_if
使用中使用默认值(::type = 0
)?
我看到一些例子,没有它就可以工作。 例如 https://foonathan.net/blog/2015/11/30/overload-resolution-4.html
#include<iostream>
#include<type_traits>
template <typename T,
typename std::enable_if<std::is_integral<T>::value, T>::type = 0>
void do_stuff(T t) {
std::cout << "do_stuff integraln";
}
template <typename T,
typename std::enable_if<std::is_class<T>::value, T>::type = 0>
void do_stuff(T t) {
std::cout << "do_stuff classn";
}
int main()
{
do_stuff(32);
return 0;
}
我收到错误消息:
temp.cpp:6:6: note: template argument deduction/substitution failed:
temp.cpp:18:13: note: couldn't deduce template parameter ‘<anonymous>’
应该推论为
template <template T, int>
void do_stuff(T t)
这是一个有效的代码。 我做错了什么?(GCC版本7.4.0)
编译器清楚地告诉你问题是什么:在你的模板声明中,你指定了一个额外的模板非类型参数,无法推断。您希望编译器如何推断出该非类型参数的正确值?从什么?
这正是上述使用std::enable_if
的技术需要默认参数的原因。这是一个虚拟参数,因此默认参数值无关紧要(0
是自然选择)。
您可以将您的示例简化为仅
template <typename T, T x>
void foo(T t) {}
int main()
{
foo(42);
}
生产
error: no matching function for call to 'foo(int)'
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter 'x'
编译器可以推导出T
是什么(T == int
),但编译器无法推断出x
的参数。
您的代码完全相同,只是您的第二个模板参数未命名(无需为虚拟参数命名)。
从您的注释来看,您似乎对代码中第二个参数的声明中存在关键字typename
感到困惑,这使您认为第二个参数也是一个类型参数。后者是不正确的。
请注意,在第二个参数的声明关键字中,typename
用于完全不同的角色。此关键字只是消除了语义的歧义
std::enable_if<std::is_class<T>::value, T>::type
它告诉编译器嵌套名称实际上表示type
类型的名称,而不是其他名称。(你可以在这里阅读typename
的这种用法:为什么我们需要typename?以及我必须在哪里以及为什么必须放置"template"和"typename"关键字?)
typename
的这种用法不会将模板的第二个参数转换为类型参数。模板的第二个参数仍然是非类型参数。
下面是另一个简化的示例,它说明了代码中发生的情况
struct S { typedef int nested_type; };
template <typename T, typename T::nested_type x>
void bar(T t)
{}
int main()
{
S s;
bar<S, 42>(s);
}
请注意,即使第二个参数的声明以typename
开头,它仍然声明一个非类型参数。
我无法重现您的错误;无论如何,我收到一个错误,用类调用do_stuff()
。通过示例
do_stuff(std::string{"abc"})
这是因为do_stuff()
变得do_stuff<std::string, std::string = 0>()
,并且模板值不能是std::string
类型(并且默认值不能为零)。
建议:重写函数,将int
作为第二个位置的值的类型
template <typename T, // .....................................VVV int, not T
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void do_stuff(T t) {
std::cout << "do_stuff integraln";
}
template <typename T, // ..................................VVV int, not T
typename std::enable_if<std::is_class<T>::value, int>::type = 0>
void do_stuff(T t) {
std::cout << "do_stuff classn";
}
这样,调用do_stuff(std::string{"abc"})
,您可以启用可接受的do_stuff<std::string, int = 0>()
。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 具有默认值的引用获取函数
- 当给定默认值时,为什么此模板参数推导失败
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 格式化浮点值:返回默认值
- 如何将数组部分初始化为某个默认值?
- asn1c 不会从 asn.1 模块中提取八位字节字符串的默认值
- 创建一个包含 c++ 默认值的环境文件
- C++(和 ROS) - 包含与前向声明引用,设置默认值和类型定义
- Makefile g++ 使用命令行中的 -D 变量进行编译,默认值
- Switch 语句(字符串)一直选择默认值,除非其为零
- 如何使用默认值将枚举声明为 extern
- 如何在提升程序选项中设置矢量<矢量>的默认值<string>
- 如何使用默认值为构造函数中的枚举赋值?
- 变量始终在函数中重置为默认值
- 如何在C++中提供模板化函数作为另一个函数的参数,默认值?
- 函数不返回默认值
- 具有公共范围与专用范围的默认值的C++的不同行为
- 在 c++ 中,如果我创建一个接受一个具有默认值的参数的构造函数 - 它会用作默认(空)构造函数吗?
- 实例化时结构字段中的默认值