【问题标题】:Add a member for certain template parameters of a template class?为模板类的某些模板参数添加成员?
【发布时间】:2014-02-26 11:50:36
【问题描述】:

考虑一个模板类:

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

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

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

这是我找到的并且我传统上使用的方法:

#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
}

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

【问题讨论】:

  • 如果您将 C++1y 列为一个选项,那么这就是 easy。 :)

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


【解决方案1】:

您可以使用继承和特化。 比如:

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 但如果您想将其推广到多个基类,使用class Helper&lt;T, B&gt;: B {}; 并使用 base- 会很方便(尤其是在不总是使用 EBO 进行多重继承的平台上)类链接。例如。 MyClass: Helper1&lt;Bla, Helper2&lt;Meh&gt;&gt; {}; 这将保证单一继承。 Boost.Operators 使用这种方法,例如
【解决方案2】:

我不太明白您声明中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&lt;std::string&gt;(); 仍然有效。

【讨论】:

  • dummy参数的用途和你的U差不多,但要避免作弊。
  • @Vincent 我向你致敬,先生 :)
【解决方案3】:

在 C++1y 概念 TS 中,我们有 requires 子句可以让您轻松做到这一点。见http://isocpp.org/files/papers/n3929.pdf——不过我可能错了。

在 C++1y 之外,您的技术使您的程序格式错误,无需诊断,因为所有函数 templates 必须至少具有一个有效的专业化。碰巧,这是一个很少强制执行的要求,因为在一般情况下解决“没有有效的专业化”涉及解决停机问题。尽管如此,程序员有责任确保所有template 函数至少有一组有效的template 参数。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    相关资源
    最近更新 更多