带有std :: experimental :: is_detected的奇怪MSVC行为 [英] Strange MSVC behaviour with std::experimental::is_detected

查看:92
本文介绍了带有std :: experimental :: is_detected的奇怪MSVC行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我基于std :: experimental :: is_detected = nofollow>在cppreference.com上的这篇文章上(部分代码在下面+可以正常工作)。

I implemented std::experimental::is_detected based on this article on cppreference.com (Part of the code is below + working repro).

在G ++和Clang ++上效果很好,但会导致MSVC出现奇怪的错误行为:被检测到似乎总是 bool_constant< true>

It works well on G++ and Clang++, but results in strange errornous behaviour with MSVC: is_detected seems to always be bool_constant<true>!

在这里您可以使用 gcc 5.x 查看正确的结果:
@ ideone.com

Here you can see the correct result using gcc 5.x: @ideone.com

但是对于MSVC 19(VS2015附带),测试始终会成功:

But with MSVC 19 (shipped with VS2015) the tests always succeed:

Z:\>cl /EHsc test.cxx
....
Z:\>test
true, true

那么,这是编译器中的已知错误吗? ?与表达式SFINAE的实现不正确有关吗?我可以使用任何解决方法来完成这项工作吗?

So, is this a known bug in the compiler? Is it related to Expression SFINAE not being implemented correctly? Is there any workaround I can use to make this work?

谢谢!

这是重现该错误的代码的一部分(我省略了接口的其余部分,除了 is_detected 以提高可读性):

Here is part of the code that reproduces the error (I omitted the rest of the interface besides is_detected to increase legibility):

#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上使用:


Strangely, directly using the void_t idiom works on 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


推荐答案

这是一种适用于最新MSVC的变通方法( (使用Visual C ++ 19.00.23720.0测试):

Here's a workaround that appears to work with recent MSVC (tested with 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 参数现在尚未使用,它只是为了保持其余的实现。)

(The dummy void parameter is unused now, it's there just to keep the rest of the implementation intact.)

这篇关于带有std :: experimental :: is_detected的奇怪MSVC行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆