C++ 检测到带有std::experimental::的奇怪MSVC行为
我实现了C++ 检测到带有std::experimental::的奇怪MSVC行为,c++,c++14,sfinae,c++17,C++,C++14,Sfinae,C++17,我实现了std::experimental::is_detectedbased(部分代码低于+working repo) 它在G++和Clang++上运行良好,但在MSVC中会导致奇怪的错误行为:被检测到似乎总是bool\u常量 在这里,您可以使用gcc 5.x查看正确的结果: 但对于MSVC 19(VS2015附带),测试总是成功的: Z:\>cl /EHsc test.cxx .... Z:\>test true, true 那么,这是编译器中已知的错误吗?它是否与表达式SF
std::experimental::is_detected
based(部分代码低于+working repo)
它在G++和Clang++上运行良好,但在MSVC中会导致奇怪的错误行为:被检测到
似乎总是bool\u常量
在这里,您可以使用gcc 5.x查看正确的结果:
但对于MSVC 19(VS2015附带),测试总是成功的:
Z:\>cl /EHsc test.cxx
....
Z:\>test
true, true
那么,这是编译器中已知的错误吗?它是否与表达式SFINAE未正确实现有关?有什么方法可以让这项工作顺利进行吗
谢谢大家!
下面是再现错误的部分代码(除了检测到
以增加易读性之外,我省略了接口的其余部分):
编译上述代码需要C++11编译器,而MSVC 2015不是C++11编译器
您在C++11遵从性方面遇到的特殊缺陷被microsoft称为“expression SFINAE”。留心它被修好了
基本上,decltype
不能用于SFINAE。用外行的话说,SFINAE是一种用于选择模板函数或类重载的技术
通常不存在解决方案。
< P>这是一个解决方案,它与最近的MSVC(用VisualC++ 19.00 .24720.0进行了测试):
#包括
模板
使用void\u t=void;
命名空间内部
{
模板
结构检测\u impl
{
使用值_t=V;
使用类型=D;
};
模板
自动检测检查(字符)
->检测\u impl;
模板
自动检测检查(int)
->decltype(void_t(),
检测_impl{});
模板
结构检测:decltype(检测\检查(0)){};
}
非等结构
{
nonesoch()=删除;
~nonesoch()=删除;
非等(非等常数&)=删除;
void运算符=(非等常数&)=删除;
};
模板类检查,typename。。。Args>
使用is_detected=typename internal::detect::value\u t;
(dummyvoid
参数现在未使用,只是为了保持实现的其余部分完好无损。)如果您正在使用基本VS2015进行此操作,请尝试至少更新1。添加了部分表达式SFINAE支持。@chris很遗憾,我已经在使用最新的CTP版本。我想说它不是一个符合标准的编译器。它确实支持大多数C++11/14功能(请看我的编辑),那么为什么直接应用void_t习惯用法是有效的,而使用detect_impl的间接方法则不行呢?@Naschkatze可能。他们的编译器在decltype
下的行为往往是脆弱的(而不是“显然不工作”)。有时我能让它发挥作用,但除非能找到它们的来源,否则我无法预测。@NathanOliver你比我更仁慈。这是允许的。公平地说,它并不假装是一个C++11编译器:\uu cplusplus==199711L
;)
#include <iostream>
// void_t: void type alias
template< typename... >
using void_t = void;
//
namespace internal
{
// Fallback case
template< typename D,
typename Void,
template< typename... > class Check,
typename... Args
>
struct detect_impl
{
using value_t = std::false_type;
using type = D;
};
// Check succeeded
template< typename D,
template< typename... > class Check,
typename... Args
>
struct detect_impl
< D, void_t< Check<Args...> >, Check, Args... >
{
using value_t = std::true_type;
using type = Check<Args...>;
};
}
// Type representing a missing type.
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template< template< typename... > class Check,
typename... Args
>
using is_detected = typename internal::detect_impl< nonesuch, void, Check, Args... >::value_t;
// Our test
template< typename T >
using is_addable_impl = decltype( std::declval<T>() + std::declval<T>() );
template< typename T >
using is_addable = is_detected<is_addable_impl, T>;
auto main(int argc, const char* arv[])
-> int
{
std::cout << std::boolalpha
<< is_addable<int>::value << ", "
<< is_addable<nonesuch>::value << std::endl;
}
#include <iostream>
#include <type_traits>
struct X {};
template< typename T, typename = void >
struct is_addable
: std::false_type
{};
template< typename T >
struct is_addable <T, std::void_t<decltype(std::declval<T>() + std::declval<T>())>>
: std::true_type
{};
int main()
{
std::cout << std::boolalpha
<< is_addable<int>::value << ", "
<< is_addable<X>::value
<< std::endl;
}
Z:\>cl /EHsc test.cxx
....
Z:\>test.exe
true, false
#include <type_traits>
template <typename...>
using void_t = void;
namespace internal
{
template <typename V, typename D>
struct detect_impl
{
using value_t = V;
using type = D;
};
template <typename D, template <typename...> class Check, typename... Args>
auto detect_check(char)
-> detect_impl<std::false_type, D>;
template <typename D, template <typename...> class Check, typename... Args>
auto detect_check(int)
-> decltype(void_t<Check<Args...>>(),
detect_impl<std::true_type, Check<Args...>>{});
template <typename D, typename Void, template <typename...> class Check, typename... Args>
struct detect : decltype(detect_check<D, Check, Args...>(0)) {};
}
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <template< typename... > class Check, typename... Args>
using is_detected = typename internal::detect<nonesuch, void, Check, Args...>::value_t;