如何定义模板选择取决于参数类是否具有typedef

时间:2017-08-19 14:21:54

标签: c++ c++11 templates

我需要什么:

template <class Context/*if Context has a Buffer typedef*/>
struct Buffer {
    typedef typename Context::Buffer type;
};

template <class Context/*if Context doesn't have a Buffer typedef*/>
struct Buffer {
    typedef std::shared_ptr<void> type;
};

如果参数类Context具有Buffer typedef,则使用它,否则将使用shared_ptr。

如何编写模板?提前谢谢。

2 个答案:

答案 0 :(得分:1)

对SFINAE使用部分类模板特化。它甚至适用于C ++ 11。

(Live example)

struct A
{
    using tag = void;  
    static constexpr const char *name = "A";
};

struct B
{    
    static constexpr const char *name = "B";
};


template <typename T> struct S
{
    static void func()
    {
        std::cout << T::name << " - no tag\n";
    };
};

template <typename T, typename = typename T::tag> using enable_if_has_tag = T;

template <typename T> struct S<enable_if_has_tag<T>>
{
    static void func()
    {
        std::cout << T::name << " - has tag\n";
    };
};

int main()
{
    S<A>::func(); // -> `A - has tag`
    S<B>::func(); // -> `B - no tag`
}

答案 1 :(得分:1)

使用void_t帮助程序非常简单:

#include <memory>
#include <type_traits>


template <typename...> using void_t = void;

template <class Context,class = void>
struct Buffer {
    typedef std::shared_ptr<void> type;
};

template <class Context>
struct Buffer<Context,void_t<typename Context::Buffer> > {
    typedef typename Context::Buffer type;
};



int main()
{
    struct Context1 {
    };

    struct Context2 {
        typedef int Buffer;
    };

    {
        using A = Buffer<Context1>::type;
        using B = std::shared_ptr<void>;
        static_assert(std::is_same<A,B>::value,"");
    }
    {
        using A = Buffer<Context2>::type;
        using B = int;
        static_assert(std::is_same<A,B>::value,"");
    }
}

请注意std::void_t在C ++ 17中,但很容易创建自己的。