C++ 如果模板专门化自定义特征,则启用\u

C++ 如果模板专门化自定义特征,则启用\u,c++,templates,C++,Templates,我试图理解std::enable_if如何在模板参数中工作 #include <type_traits> #include <iostream> #include <memory> using namespace std; class Interface {}; class Value {}; class Stream { public: template<typename T, typename enable

我试图理解std::enable_if如何在模板参数中工作

#include <type_traits>
#include <iostream>
#include <memory>

using namespace std;


class Interface {};
class Value {};


class Stream
{
public:

    template<typename T,
            typename enable_if<
                is_base_of< Interface, T>{}
            >::type* = nullptr>
    void
    write(const shared_ptr<T>& v)
    {
        cerr << "Writing interface class" << endl;
    }

    template<typename T,
            typename enable_if<
                is_base_of< Value, T>{}
            >::type* = nullptr>
    void
    write(const shared_ptr<T>& v)
    {
        cerr << "Writing value class" << endl;
    }
};

class UserI : public Interface{};
class User : public Value{};

int main(int, char**)
{

    auto interface = make_shared<UserI>();
    auto value = make_shared<User>();

    Stream s;
    s.write(interface);
    s.write(value);

    return 0;
}
#包括
#包括
#包括
使用名称空间std;
类接口{};
类值{};
类流
{
公众:
模板{}
>::type*=nullptr>
无效的
写入(常量共享\u ptr&v)
{
瑟尔
无效的
写入(常量共享\u ptr&v)
{
cerr::价值;
};
类流
{
公众:
模板::类型*=nullptr>
无效的
写入(常量共享\u ptr&v)
{
瑟尔

就我个人而言,我认为在您的情况下,标记分派方法会更干净、更易于维护。下面是一个可能的实现:

class Stream
{
private:
    struct interface_tag{};
    struct value_tag{};
    //if you ever need more tags, add them here
    struct invalid_tag{};

    template <typename T>
    struct get_tag {
        static interface_tag tagger (Interface*);
        static value_tag tagger (Value*);
        //add any mappings for other tags
        static invalid_tag tagger (...);

        using tag = decltype(tagger(std::declval<T*>()));
    };

    //convenience alias
    template <typename T> using tag_t = typename get_tag<T>::tag;

public:
    //clean public interface
    template <typename T>
    void write (const shared_ptr<T>& v) {
        write(v, tag_t<T>{});   
    }

private:
    //no more horrible std::enable_if
    template<typename T>
    void
    write(const shared_ptr<T>& v, interface_tag)
    {
        cerr << "Writing interface class" << endl;
    }

    template<typename T>
    void
    write(const shared_ptr<T>& v, value_tag)
    {
        cerr << "Writing value class" << endl;
    }
};
类流
{
私人:
结构接口_标记{};
结构值_标记{};
//如果您需要更多标签,请添加到此处
结构无效的_标记{};
模板
结构获取标签{
静态接口\标签标记器(接口*);
静态值标签(值*);
//为其他标记添加任何映射
静态无效的_标记标记器(…);
使用tag=decltype(tagger(std::declval());
};
//方便别名
使用tag_t=typename get_tag::tag的模板;
公众:
//干净的公共界面
模板
无效写入(常量共享\u ptr&v){
写入(v,tag_{});
}
私人:
//没有更可怕的std::如果
模板
无效的
写入(常数共享\u ptr&v、接口\u标签)
{
瑟尔
test_t2.cc: In function ‘int main(int, char**)’:
test_t2.cc:58:26: error: no matching function for call to ‘Stream::write(std::shared_ptr<UserI>&)’
        s.write(interface);
                        ^
test_t2.cc:58:26: note: candidates are:
test_t2.cc:32:9: note: template<class T, typename std::enable_if<is_interface<T>{}>::type* <anonymous> > void Stream::write(const std::shared_ptr<_Tp1>&)
        write(const shared_ptr<T>& v)
        ^
test_t2.cc:32:9: note:   template argument deduction/substitution failed:
test_t2.cc:30:28: error: could not convert template argument ‘is_interface<UserI>{}’ to ‘bool’
                >::type* = nullptr>
typename enable_if<
    is_base_of< Interface, T>{}
>::type* = nullptr
template<typename T,
        typename enable_if<
            is_interface<T>::value //here
        >::type* = nullptr>
void
write(const shared_ptr<T>& v)
class Stream
{
private:
    struct interface_tag{};
    struct value_tag{};
    //if you ever need more tags, add them here
    struct invalid_tag{};

    template <typename T>
    struct get_tag {
        static interface_tag tagger (Interface*);
        static value_tag tagger (Value*);
        //add any mappings for other tags
        static invalid_tag tagger (...);

        using tag = decltype(tagger(std::declval<T*>()));
    };

    //convenience alias
    template <typename T> using tag_t = typename get_tag<T>::tag;

public:
    //clean public interface
    template <typename T>
    void write (const shared_ptr<T>& v) {
        write(v, tag_t<T>{});   
    }

private:
    //no more horrible std::enable_if
    template<typename T>
    void
    write(const shared_ptr<T>& v, interface_tag)
    {
        cerr << "Writing interface class" << endl;
    }

    template<typename T>
    void
    write(const shared_ptr<T>& v, value_tag)
    {
        cerr << "Writing value class" << endl;
    }
};