C++ 为sfinae使用别名模板:语言允许吗?
我刚刚发现了以下技术。它看起来非常接近于所提出的概念语法之一,在Clang、GCC和MSVC上都能完美地工作C++ 为sfinae使用别名模板:语言允许吗?,c++,c++11,language-lawyer,sfinae,C++,C++11,Language Lawyer,Sfinae,我刚刚发现了以下技术。它看起来非常接近于所提出的概念语法之一,在Clang、GCC和MSVC上都能完美地工作 template <typename T, typename = typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type> using require_rvalue = T&&; template <typename T> vo
template <typename T, typename = typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type>
using require_rvalue = T&&;
template <typename T>
void foo(require_rvalue<T> val);
模板
使用require\u rvalue=T&;
模板
void foo(需要正确的值);
我试图通过搜索请求(如“sfinae in type alias”)找到它,但什么也没有得到。这种技术有名字吗?这种语言真的允许吗
完整示例:
#include <type_traits>
template <typename T, typename = typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type>
using require_rvalue = T&&;
template <typename T>
void foo(require_rvalue<T>)
{
}
int main()
{
int i = 0;
const int ic = 0;
foo(i); // fail to compile, as desired
foo(ic); // fail to compile, as desired
foo(std::move(i)); // ok
foo(123); // ok
}
#包括
模板
使用require\u rvalue=T&;
模板
void foo(要求正确值)
{
}
int main()
{
int i=0;
常数int ic=0;
foo(i);//根据需要编译失败
foo(ic);//根据需要编译失败
foo(std::move(i));//好的
foo(123);//好的
}
[…]语言真的允许吗
关于这个名字我什么也说不出来,但我觉得这是肯定的
有关措辞如下:
当模板id引用别名模板的专门化时,它相当于通过将其模板参数替换为别名模板的类型id中的模板参数而获得的关联类型
还有sfinae规则:
只有函数类型、其模板参数类型及其显式说明符的直接上下文中的无效类型和表达式才能导致推断失败
采用require\u rvalue
类型的参数,其行为就好像我们替换了该别名,这要么给了我们一个T&
或替换失败-替换失败可以说是在替换的直接上下文†中,因此“sfinae友好”而不是硬错误。请注意,尽管默认类型参数未使用,但由于(void\t
规则),我们增加了:
但是,如果模板id是依赖的,则后续的模板参数替换仍然适用于模板id
这确保我们仍然替换到默认的类型参数中,以触发所需的替换失败
问题的第二个未提及的部分是,这是否真的可以作为转发引用。规则如下:
转发引用是对cv非限定模板参数的右值引用,该参数不表示类模板的模板参数(在类模板参数推导([over.match.class.decrete])。如果P是一个转发引用,并且参数是一个左值,那么类型“对a的左值引用”将代替a用于类型推断
具有一个模板参数(其关联类型是对其cv模板参数的右值引用)的别名模板是否被视为转发引用?嗯,[temp.alias]/2说require\u-rvalue
相当于T&
,而T&
是正确的。所以可以说。。。嗯
所有的编译器都这样对待它,这当然是一个很好的验证
†尽管如此,请注意直接上下文的存在和缺乏实际定义,以及其中的示例,该示例还依赖于默认参数的替换失败,该问题指出存在实现分歧 > P>它是工作的,并且允许,因为它对标准允许的广泛使用的C++特性进行了中继:
模板
void foo(T&&v,typename std::enable_if::type*=nullptr)
{ /* ... */ }
我们无法推断实际参数,如void foo(typename std::enable_if::type&&)
(),但可以使用模板别名来解决此限制(这是我在问题中介绍的技巧)模板
无效foo(T&v)
{ /* ... */ }
模板结构Alloc{/*…*/};
模板使用向量=向量;
模板
作废流程(Vec&v)
{ /* ... */ }
<>我接受了巴里的回答,并把这一个(集中的信息和每一个方面的伎俩使用),因为很多人(包括我)害怕C++标准的巫术语言关于模板演绎的东西。我也从来没见过。有趣的是,别名替换必须在类型推断之前发生,以便认识到参数是转发引用,并使推断
T
成为可能。并且别名替换必须在类型推断之后发生,以确定默认模板参数是否有效。但是,我很确定这正是[temp.alias]/4的意思,“但是,如果模板id是依赖的,后续的模板参数替换仍然适用于模板id。”是的,我注意到我的评论和您的编辑相隔几秒钟。是的,这是标准的一部分,由严格的手工操作指定。
template <typename T>
void foo(T&& v, typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type* = nullptr)
{ /* ... */ }
template <typename T, typename std::enable_if<std::is_rvalue_reference<T&&>::value>::type* = nullptr>
void foo(T&& v)
{ /* ... */ }
template<class T> struct Alloc { /* ... */ };
template<class T> using Vec = vector<T, Alloc<T>>;
template<class T>
void process(Vec<T>& v)
{ /* ... */ }