我基于on this article on cppreference.com实施了std::experimental::is_detected
(部分代码低于+工作重复)。
它适用于G ++和Clang ++,但导致MSVC出现奇怪的错误行为:is_detected
似乎总是bool_constant<true>
!
在这里,您可以使用gcc 5.x
查看正确的结果:
@ideone.com
但是使用MSVC 19(VS2015附带),测试总是成功:
Z:\>cl /EHsc test.cxx
....
Z:\>test
true, true
那么,这是编译器中的已知错误吗?是否与表达SFINAE无法正确实现有关?我可以用它来解决这个问题吗?
谢谢!
以下是重现错误的代码的一部分(除了is_detected
之外我省略了接口的其余部分以提高可读性):
#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;
}
编辑:奇怪的是,直接使用void_t成语可以在MSVC上运行:
#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
答案 0 :(得分:4)
您需要一个C ++ 11编译器来编译上面的代码,而MSVC 2015不是C ++ 11编译器。
您遇到的C ++ 11兼容性的特殊缺陷被microsoft称为“表达式SFINAE”。留意它是否被修复。
基本上,decltype
不能用于SFINAE。在外行人看来,SFINAE是您用于选择模板函数或类的重载的技术。
通常没有解决方法。
答案 1 :(得分:4)
这是一个似乎与最近的MSVC一起使用的解决方法(使用Visual C ++ 19.00.23720.0测试):
#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;
(虚拟void
参数现在尚未使用,只是为了保持其余的实现不变。)