【发布时间】:2016-02-26 20:28:46
【问题描述】:
我实现了基于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
那么,这是编译器中的一个已知错误吗?是否与未正确实施 Expression 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
【问题讨论】:
-
如果您正在尝试使用基本 VS2015 进行此操作,请至少尝试更新 1。添加了部分表达式 SFINAE 支持。
-
@chris 很遗憾,我已经在使用最新的 CTP 版本了。