std::get
似乎不是SFINAE友好的,如下面的测试用例所示:
templateauto foo(C &c) -> decltype(std::get (c)) { return std::get (c); } template void foo(...) { } int main() { std::tuple tuple{42}; foo (tuple); // Works fine foo (tuple); // Crashes and burns }
在Coliru上看到它
目标是将第二次呼叫foo
转向第二次超载.在实践中,libstdc ++给出:
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.0/../../../../include/c++/6.3.0/tuple:1290:14: fatal error: no matching function for call to '__get_helper2' { return std::__get_helper2<_Tp>(__t); } ^~~~~~~~~~~~~~~~~~~~~~~
libc ++更直接,直接static_assert
引爆:
/usr/include/c++/v1/tuple:801:5: fatal error: static_assert failed "type not found in type list" static_assert ( value != -1, "type not found in type list" ); ^ ~~~~~~~~~~~
我真的不想实现洋葱层检查是否C
是一个std::tuple
专业化,并寻找T
其参数内...
有没有理由std::get
不对SFINAE友好?有没有比上面概述的更好的解决方法?
我发现了一些事情std::tuple_element
,但没有std::get
.
std::get
根据[tuple.elem]显然不是SFINAE友好的:
templateconstexpr T& get(tuple & t) noexcept; // and the other like overloads 要求:类型
T
恰好出现一次Types...
.否则,该计划是不正确的.
std::get
也明确不是SFINAE友好的.
至于其他问题:
有没有理由
std::get
不对SFINAE友好?
不知道.通常,这不是需要SFINAE编辑的一点.所以我想这不是需要做的事情.滚动查看一堆不可行的候选选项,比较容易理解硬错误.如果您认为有令人信服的理由对std::get
SFINAE友好,您可以提交LWG问题.
有没有比上面概述的更好的解决方法?
当然.您可以编写自己的SFINAE友好版本get
(请注意,它使用C++ 17 倍表达式):
template::value + ...) == 1, int> = 0> constexpr T& my_get(tuple & t) noexcept { return std::get (t); }
然后按照你的意愿去做.
不要SFINAE上std::get
; 这是不允许的.
以下是两种相对友好的方法来测试你是否可以using std::get; get
:
templateusing can_get=std::integral_constant ::value>; namespace helper{ template struct can_get_type:std::false_type{}; template struct can_get_type >: std::integral_constant +...)==1> {}; } template using can_get=typename helpers::can_get_type ::type;
那你的代码是:
template{},int> =0> decltype(auto) foo(C &c) { return std::get (c); }