C++ constexpr模板参数古怪

C++ constexpr模板参数古怪,c++,templates,language-lawyer,constexpr,C++,Templates,Language Lawyer,Constexpr,GCC(5.3)和Clang(3.8)声称测试中的第一行是坏的,但第二行是好的。MSVC(2015.2)说,两者都是无效的 template< typename N, typename T > void f( N n, T t ) { std::get< n >( t ); } void test() { std::get< std::integral_constant< size_t, 0 >() >( std::make_tuple(

GCC(5.3)和Clang(3.8)声称
测试中的第一行是坏的,但第二行是好的。MSVC(2015.2)说,两者都是无效的

template< typename N, typename T >
void f( N n, T t ) { std::get< n >( t ); }
void test() {
    std::get< std::integral_constant< size_t, 0 >() >( std::make_tuple( 123 ) ); // not ok
    f( std::integral_constant< size_t, 0 >(), std::make_tuple( 123 ) ); // ok for gcc, clang, but not msvc
}
模板
void f(nn,tt){std::get(T);}
无效测试(){
std::get()>(std::make_tuple(123));//不正常
f(std::integral_constant(),std::make_tuple(123));//对于gcc、clang来说是可以的,但对于msvc来说不是
}
根据标准,到底有什么区别?这个代码一开始合法吗


第一行的叮当声错误:

In file included from main.cpp:2:
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/tuple:874:34: error: no matching function for call to '__get_helper2'
    { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); }
                                 ^~~~~~~~~~~~~~~~~~~~~~~
main.cpp:10:10: note: in instantiation of function template specialization 'std::get<std::integral_constant<unsigned long, 0> (), int>' requested here
    std::get<std::integral_constant<size_t, 0>()>( std::make_tuple( 123 ) ); // not ok
         ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/tuple:856:5: note: candidate template ignored: could not match '_Tuple_impl' against 'tuple'
    __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
    ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../include/c++/5.3.0/tuple:861:5: note: candidate template ignored: could not match '_Tuple_impl' against 'tuple'
    __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
    ^
1 error generated.
在main.cpp:2中包含的文件中:
/usr/local/bin/./lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../../../../../include/c++/5.3.0/tuple:874:34:错误:调用“\uu get\u helper2”没有匹配的函数
{return std::forward(std::u get_helper2(u_t));}
^~~~~~~~~~~~~~~~~~~~~~~
main.cpp:10:10:注意:在函数模板专门化的实例化中,此处请求“std::get”
std::get(std::make_tuple(123));//不好
^
/usr/local/bin/./lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../../../../include/c++/5.3.0/tuple:856:5:注意:已忽略候选模板:无法将“\u tuple\u impl”与“tuple”匹配
__获取帮助2(\u Tuple\u impl&\u t)无异常
^
/usr/local/bin/./lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../../../../include/c++/5.3.0/tuple:861:5:注意:已忽略候选模板:无法将“\u tuple\u impl”与“tuple”匹配
__get_helper2(const_Tuple_impl&_t)无异常
^
生成1个错误。
gcc错误:

In file included from main.cpp:2:0:
/usr/local/include/c++/5.3.0/tuple: In instantiation of 'constexpr _Tp&& std::get(std::tuple<_Elements ...>&&) [with _Tp = std::integral_constant<long unsigned int, 0ul>(); _Types = {int}]':
main.cpp:10:75:   required from here
/usr/local/include/c++/5.3.0/tuple:874:57: error: no matching function for call to '__get_helper2(std::tuple<int>&)'
     { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); }
                                                         ^
/usr/local/include/c++/5.3.0/tuple:856:5: note: candidate: template<class _Head, long unsigned int __i, class ... _Tail> constexpr _Head& std::__get_helper2(std::_Tuple_impl<__i, _Head, _Tail ...>&)
     __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
     ^
/usr/local/include/c++/5.3.0/tuple:856:5: note:   template argument deduction/substitution failed:
/usr/local/include/c++/5.3.0/tuple:874:57: note:   mismatched types 'std::integral_constant<long unsigned int, 0ul>()' and 'int'
     { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); }
                                                         ^
/usr/local/include/c++/5.3.0/tuple:874:57: note:   'std::tuple<int>' is not derived from 'std::_Tuple_impl<__i, std::integral_constant<long unsigned int, 0ul>(), _Tail ...>'
/usr/local/include/c++/5.3.0/tuple:861:5: note: candidate: template<class _Head, long unsigned int __i, class ... _Tail> constexpr const _Head& std::__get_helper2(const std::_Tuple_impl<__i, _Head, _Tail ...>&)
     __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
     ^
/usr/local/include/c++/5.3.0/tuple:861:5: note:   template argument deduction/substitution failed:
/usr/local/include/c++/5.3.0/tuple:874:57: note:   mismatched types 'std::integral_constant<long unsigned int, 0ul>()' and 'int'
     { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); }
                                                         ^
/usr/local/include/c++/5.3.0/tuple:874:57: note:   'std::tuple<int>' is not derived from 'const std::_Tuple_impl<__i, std::integral_constant<long unsigned int, 0ul>(), _Tail ...>'
在main.cpp:2:0中包含的文件中:
/usr/local/include/c++/5.3.0/tuple:constepr\u Tp&&std::get(std::tuple&)[with _Tp=std::integral\u constant();_Types={int}]的实例化中:
main.cpp:10:75:从这里开始需要
/usr/local/include/c++/5.3.0/tuple:874:57:错误:对“\uu get\u helper2(std::tuple&)”的调用没有匹配的函数
{return std::forward(std::u get_helper2(u_t));}
^
/usr/local/include/c++/5.3.0/tuple:856:5:注:候选:模板constepr\u Head&std:\u get\u helper2(std:\u tuple\u impl&)
__获取帮助2(\u Tuple\u impl&\u t)无异常
^
/usr/local/include/c++/5.3.0/tuple:856:5:注意:模板参数推断/替换失败:
/usr/local/include/c++/5.3.0/tuple:874:57:注意:不匹配的类型“std::integral_constant()”和“int”
{return std::forward(std::u get_helper2(u_t));}
^
/usr/local/include/c++/5.3.0/tuple:874:57:注意:“std::tuple”不是从“std::\u tuple\u impl”派生的
/usr/local/include/c++/5.3.0/tuple:861:5:注:候选:模板constepr const\u Head&std::\u get\u helper2(const std:\u tuple\u impl&)
__get_helper2(const_Tuple_impl&_t)无异常
^
/usr/local/include/c++/5.3.0/tuple:861:5:注意:模板参数推断/替换失败:
/usr/local/include/c++/5.3.0/tuple:874:57:注意:不匹配的类型“std::integral_constant()”和“int”
{return std::forward(std::u get_helper2(u_t));}
^
/usr/local/include/c++/5.3.0/tuple:874:57:注意:“std::tuple”不是从“const std::_tuple_impl”派生的

tl;dr我认为gcc和clang在这两种情况下的行为都是正确的


你的两个电话之间有细微的差别。让我添加一个别名来说明:

using Zero = std::integral_constant<size_t, 0>;
auto tuple = std::make_tuple(123);
n
不是类型-它只是一个值。由于
std::integral\u constant
有一个
constepr操作符size\u t()
,因此使用该操作符,并最终调用
std::get()
,这就是您所期望的

同样,也可以通过简单地使用大括号初始化来实现:

std::get<Zero{}>(tuple);
std::get(元组);

因为
Zero{}
绝对不是一种类型

你能告诉我们你犯了什么错误吗?我不太喜欢在这里贴满了文字,但这里是要点。MSVC下的第二行:“'std::get':未找到匹配的重载函数”。第一行:沿着指向
std::tuple
内部结构的类似行出现的各种常见的混乱。@vpozdyayev这些错误帮助很大——正是这些错误消息让我明白了问题所在。“这不仅仅是胡言乱语,”巴里说得很公平。FWIW,我甚至不确定该引用谁/哪些错误(对于MSVC,这将是另外两个报告)。虽然如果我们把自己限制在GCC/Clang上,那就更合理了。啊,最令人烦恼的解析:)。。。近年来C++变得非常方便,我完全忘记了。实际上…std::get(tuple)行仅在Clang中有效,但在GCC中无效(“在常量表达式中'n'的值不可用”/“n'未声明为'constexpr'))。这会是一个GCC错误吗?@vpozdyayev它是你工作案例的一个简化版本,实际上不是有效的代码。不过,Clang似乎同意你对这个代码的推理。这可能值得提出一个新问题。
Zero n;
std::get<n>(tuple);
std::get<Zero{}>(tuple);