C++ 用于泛型类型上泛型操作的SFINAE

C++ 用于泛型类型上泛型操作的SFINAE,c++,templates,c++17,sfinae,enable-if,C++,Templates,C++17,Sfinae,Enable If,我有 可以用不同类型(Foo、Bar、int等)构造的类值 类值应该具有常见的操作,如可以替换的 std::ostream &operator<<(std::ostream &os, const Value &value) { // ... } 您可以添加包装以仅强制一次转换: template <typename T> struct OneConversion { OneConversion(const T& t) :

我有

  • 可以用不同类型(Foo、Bar、int等)构造的类值

  • 类值应该具有常见的操作,如可以替换的

    std::ostream &operator<<(std::ostream &os, const Value &value)
    {
        // ...
    }
    

    您可以添加包装以仅强制一次转换:

    template <typename T>
    struct OneConversion
    {
        OneConversion(const T& t) : t(t) {}
    
        operator const T&() const {return t;}
    
        const T& t;  
    };
    
    template <typename T>
    struct isOneConversion : std::false_type {};
    
    template <typename T>
    struct isOneConversion<OneConversion<T>> : std::true_type {};
    
    struct Value {
        template<typename T, std::enable_if_t<!isOneConversion<T>::value>* = nullptr>
        Value(T) {}
    };
    
    std::ostream &operator<<(std::ostream &os, const Value &value) {
    
        auto visitor = [&](auto a) -> decltype(os << OneConversion<decltype(a)>(a)) {
            return os << OneConversion<decltype(a)>(a);
        };
    
        // Works
        visitor(Bar{});
    
        visitor(Foo{}); // Error as expected.
    
        return os;
    }
    
    模板
    结构转换
    {
    OneConversion(const T&T):T(T){}
    运算符常量T&()常量{return T;}
    康斯特T&T;
    };
    模板
    结构isOneConversion:std::false_type{};
    模板
    结构isOneConversion:std::true_type{};
    结构值{
    模板*=nullptr>
    值(T){}
    };
    
    std::ostream&operator不修改
    std::ostream&operator的签名
    
    std::ostream &operator<<(std::ostream &os, const Value &value)
    {
        // ...
    }
    
    template <typename T, typename = std::enable_if_t<std::is_same_v<T, Value>>>
    std::ostream &operator<<(std::ostream &os, const T &value)
    {
        // ...
    }
    
    ...
    main.cpp:29:12: error: no match for call to '(operator<<(std::ostream&, const T&) [with T = Value; <template-parameter-1-2> = void; std::ostream = std::basic_ostream<char>]::<lambda(auto:1)>) (Foo)'
     visitor(Foo{});
     ~~~~~~~^~~~~~~
    ...
    
    template <typename T>
    struct OneConversion
    {
        OneConversion(const T& t) : t(t) {}
    
        operator const T&() const {return t;}
    
        const T& t;  
    };
    
    template <typename T>
    struct isOneConversion : std::false_type {};
    
    template <typename T>
    struct isOneConversion<OneConversion<T>> : std::true_type {};
    
    struct Value {
        template<typename T, std::enable_if_t<!isOneConversion<T>::value>* = nullptr>
        Value(T) {}
    };
    
    std::ostream &operator<<(std::ostream &os, const Value &value) {
    
        auto visitor = [&](auto a) -> decltype(os << OneConversion<decltype(a)>(a)) {
            return os << OneConversion<decltype(a)>(a);
        };
    
        // Works
        visitor(Bar{});
    
        visitor(Foo{}); // Error as expected.
    
        return os;
    }
    
    auto visitor = [&](auto a) -> decltype(
                                  static_cast<std::ostream&(*)(std::ostream&, const decltype(a)&)>(&operator<<)
                                 (os, a)
                                 )
    {
        return os << a;
    };
    
    error: invalid static_cast from type '<unresolved overloaded function type>' to type 'std::ostream& (*)(std::ostream&, const Foo&