为模板类的某些模板参数添加成员?

时间:2014-02-26 11:50:37

标签: c++ templates c++11 metaprogramming template-specialization

考虑一个模板类:

template <class First, class Second, class Third, class Fourth>
class MyClass;

为某些模板参数集添加成员函数的正确方法是什么?

例如,当f()Second时,如何添加成员std::string()

这是我发现的方法,我传统上使用:

#include <iostream>
#include <type_traits>
#include <array>

template <class Container>
struct Array
{
    Container data;
    template <class... Dummy, 
              class = typename std::enable_if<sizeof...(Dummy) == 0>::type,
              class = typename std::enable_if<
                               std::tuple_size<
                               typename std::conditional<sizeof...(Dummy), 
                                                         Container, 
                                                         Container
                                                         >::type
                               >::value == 1
                               >::type
              >
    inline typename Container::value_type& value(Dummy...)
    {return data[0];}
};


int main()
{
    Array<std::array<double, 0>> array0; // Does not have the value() member
    Array<std::array<double, 1>> array1; // Have the value() member
    Array<std::array<double, 2>> array2; // Does not have the value() member
    Array<std::array<double, 3>> array3; // Does not have the value() member
}

它运作良好,但它更像是一种元编程技巧,而不是干净/标准的方法。

3 个答案:

答案 0 :(得分:4)

您可以使用继承和专业化。 类似的东西:

template <typename T> struct Helper2 {};

template <> struct Helper2<std::string>
{
    void f() {};
};

template <class First, class Second, class Third, class Fourth>
struct MyClass : public Helper2<Second>
{
    // Normal code.
};

int main()
{
    MyClass<std::string, int, std::string, std::string> c1;
    MyClass<int, std::string, int, int> c2;
    //c1.f();     // this is an error
    c2.f();    // this works
    return 0;
}

答案 1 :(得分:1)

我在宣言中并没有达到Dummy的目的。可以使用功能参数列表中根本未使用的两个默认模板参数来完成:

#include <type_traits>
#include <string>

template <class First> // arguments ommited for brevity
struct MyClass {
    template<
        typename U = First,
        typename = typename std::enable_if< std::is_same<U, std::string>::value >::type
    >
    void f() {}
};

int main()
{
    MyClass<int> c1;
    MyClass<std::string> c2;
    // this is an error
    // c1.f();
    c2.f();    // this works
}

Live example.

请注意,可以作弊:c1.f<std::string>();仍然有效。

答案 2 :(得分:0)

在C ++ 1y概念TS中,我们有requires个子句,可以让你轻松完成。见http://isocpp.org/files/papers/n3929.pdf - 但我可能错了。

在C ++之外,你的技术会使你的程序格式错误而不需要诊断,因为所有函数template s 必须至少有一个有效的特化。实际上,这是一个非常罕见的强制要求,因为在一般情况下解决“没有有效的专业化”涉及解决暂停问题。尽管如此,程序员有责任确保所有template函数至少有一组有效的template参数。

我发现在C ++ 11中对零参数函数严格合法的方法是使用基于CRTP的类特化,它消除了CRTP基础专业化中的方法。

另一种方法是创建一个私有的,不可访问的类型,并使其成为在您要禁用它的情况下创建合法专业化的唯一方法。然后在课堂上私下你可以作弊,但在外面你不能作弊。