我试图理解使用std::enable_if<>
的模板函数的两个不同版本。
版本1:
template<class T, typename std::enable_if<std::is_convertible<T, std::string_view>::value, T>::type* = nullptr>
void foo(const T& msg);
版本2:
template<class T, typename = typename std::enable_if<std::is_convertible<T, std::string_view>::value>::type>
void foo(const T& msg);
如果我理解正确的话,如果满足条件,它们应该转换为:
// Version 1
template<class T, T* = nullptr>
void foo(const T& msg);
// Version 2
template<class T, typename = void>
void foo(const T& msg);
两个版本都可以通过以下方式调用:
std::string s = "Test";
foo(s);
这两个版本有什么不同?什么时候应该使用一个?
第二个问题
由于我的一个错误,我发现如果缺少一个类型名,版本2也会编译:
//Correct Version 2 like above:
template<class T, typename = typename std::enable_if<std::is_convertible<T, std::string_view>::value>::type>
void foo(const T& msg);
// My "faulty" version, also works. Is this correct too?
template<class T, typename = std::enable_if<std::is_convertible<T, std::string_view>::value>::type>
void foo(const T& msg);
第二个(错误的)版本也是正确的吗?我认为std::enable_if<>
确实需要一个typename
在它前面。
1条答案
按热度按时间zwghvu4y1#
如何约束模板?
如果您不限于与旧的C标准(C20之前)兼容,并且不需要引用模板类型,约束只涉及一个模板参数,则首选最少的样板选项:
否则,请使用稍微详细一点的形式:
表单#2给出了模板类型的名称,如果约束包含多个模板参数,它仍然不能直接应用于旧的C++,但是约束的位置与旧的C++
enable_if
用法兼容:以下选项也可用,但我会坚持#1或#2:
对于
enable_if
,有三个选项:选项#7(“版本2”)不太可取,因为默认模板参数不参与函数签名。因此,一旦有两个重载,它就不明确了。并且重载集会增长。
选项#6不适用于构造函数,因为构造函数没有返回类型。但是,在#6中,你可以方便地命名函数参数。
选项#5是最通用的SFINAE选项。如果您必须使用SFINAE,请首选它。
关于问题#2,C++20中对类型名的放宽,在这里和here中进行了描述