C++ gcc vs.clang:“;“不完整类型的无效使用”;使用std::declval和模板专门化

C++ gcc vs.clang:“;“不完整类型的无效使用”;使用std::declval和模板专门化,c++,c++11,gcc,clang,sfinae,C++,C++11,Gcc,Clang,Sfinae,我有一个方法fun,它包含在用于部分专门化的结构Impl中。检查是否派生自\u模板用于确定泛型Impl::fun是否可用于派生自特定模板的类型。否则,Impl将显式地部分专用化 #include <iostream> template <typename T, typename U> struct Base{}; // Forward declaration struct Foo; struct Bar; template <template<typen

我有一个方法
fun
,它包含在用于部分专门化的结构
Impl
中。检查
是否派生自\u模板
用于确定泛型
Impl::fun
是否可用于派生自特定模板的类型。否则,
Impl
将显式地部分专用化

#include <iostream>

template <typename T, typename U>
struct Base{};

// Forward declaration
struct Foo;
struct Bar;

template <template<typename...> class T, typename U>
struct is_derived_from_template
{
private:
    template<typename... Args>
    static decltype(static_cast<const T<Args...>&>(std::declval<U>()), std::true_type{}) test(const T<Args...>&);
    static std::false_type test(...);
public:
    static constexpr bool value = decltype(test(std::declval<U>()))::value;
};

template <typename T, typename = void>
struct Impl
{
    static void fun(T& x);
};

template <typename T>
struct Impl<T, typename std::enable_if<is_derived_from_template<Base, T>::value>::type>
{
    static void fun(T& base)
    {
        std::cout << "Base" << std::endl;
    }
};

template <>
void Impl<Foo>::fun(Foo& t)
{
    std::cout << "Foo" << std::endl;
}

struct Foo {};
struct Bar : Base<int,double> {};

int main()
{
    Foo foo;
    Bar bar;

    Impl<Foo>::fun(foo);

    Impl<Bar>::fun(bar);
}

  • 这两个编译器中哪一个是正确的
  • 如何修改代码以使其与gcc一起工作

  • 1.
    Clang
    的编译方式与传统编译器(如
    GCC
    )略有不同
    GCC
    是正确的,因为与
    Clang
    相比,它“传统地”解析代码,并且您应该在使用它们之前定义类型。
    你可以找到一个比较

    2.更改:

    // Forward declaration
    struct Foo;
    struct Bar;
    
    致:

    structfoo{};
    结构条:基{};
    

    为我工作。

    1.
    Clang
    的编译方式与传统编译器(如
    GCC
    )略有不同
    GCC
    是正确的,因为与
    Clang
    相比,它“传统地”解析代码,并且您应该在使用它们之前定义类型。
    你可以找到一个比较

    2.更改:

    // Forward declaration
    struct Foo;
    struct Bar;
    
    致:

    structfoo{};
    结构条:基{};
    
    为我工作。

    减少到

    #include <utility>
    void f(...);
    class C;
    using type = decltype(f(std::declval<C>()));
    
    尽管您应该谨慎,不允许使用不完整的类型实例化
    is_derived_from_template
    ,因为如果完整的类型是从指定的模板派生的,则很容易导致ODR冲突。

    减少到

    #include <utility>
    void f(...);
    class C;
    using type = decltype(f(std::declval<C>()));
    
    尽管您应该谨慎,不允许使用不完整的类型实例化
    is_derived_from_template
    ,因为如果完整的类型是从指定的模板派生的,则很容易导致ODR冲突

    #include <utility>
    void f(...);
    class C;
    using type = decltype(f(std::declval<C>()));
    
    template <template<typename...> class T, typename U>
    struct is_derived_from_template
    {
    private:
        template<typename... Args>
        static decltype(static_cast<const T<Args...>&>(std::declval<U>()), std::true_type{}) test(const T<Args...>*);
        static std::false_type test(...);
    public:
        static constexpr bool value = decltype(test(std::declval<U*>()))::value;
    };