refactor MANY函数优雅地接收任何类型的参数(template <any>)

时间:2017-03-20 09:34:04

标签: c++ function templates

我有自定义数据结构。

template<class T> class MyArray3D{
    public: void setElement(const int* index,const T& t){
        //do something about "index[0,1,2]"
    }
    public: T& get(const int* index){
        //do something about "index[0,1,2]"
    }
    public: void reserve(const int* index1,const int* index2){
        //do something about "index1,2[0,1,2]" (e.g. index can be negative)
    }
    //about 20 functions, and some fields
};

一切都很好。它目前被许多类使用 然后我希望这些函数接受具有index

的任何内容(operator[]

我糟糕的解决方案

这是一种正确(但不是很好)的方法 我将const int*更改为template INT_ARRAY: -

template<class T> class MyArray3D{
    public: template<class IARRAY> void setElement(IARRAY index,const T& t){
        //do something about "index[0,1,2]"
    }
    public: template<class IARRAY> T& get(IARRAY index){
        //do something about "index[0,1,2]"
    }
    public: template<class IARRAY1,class IARRAY2> 
      void reserve(IARRAY1 index1,IARRAY2 index2){
        //do something about "index1,2[0,1,2]" (e.g. index can be negative)
    }
    //about 20 functions, and some fields
};

上述重构是乏味的。我必须为所有功能做到这一点。

如果一个函数有4 const int*,它将以template<class IARRAY1,class IARRAY2,class IARRAY3,class IARRAY4>为前缀 - 太丑了。

问题

如何优雅地重构上述功能(重复性较低,代码较短)?

我在做着类似的事情: -

template<class T> class MyArray3D{
    using IARRAY1 = please don't care about my type; ????
    public: void setElement(IARRAY1 index,const T& t);
    public: T& get(IARRAY1 index);
    public: void reserve(IARRAY1 index1,IARRAY1 index2);
};

以下是相关问题:

2 个答案:

答案 0 :(得分:3)

不幸的是,如果你想要模板函数参数演绎并接受任何类型,这是正确的方法,尽管它不简洁。

希望将来我们会得到abbreviated Concepts Lite syntax,这样你就可以做到:

concept bool Indexable = /* ... */;

template<class T> class MyArray3D{
public: 
    void setElement(Indexable index, const T& t);
    T& get(Indexable index);
    void reserve(Indexable index1, Indexable index2);
};

答案 1 :(得分:1)

一些想法:

template <typename... T>
void foo(T&&... args)
{
    auto tuple = std::make_tuple(std::forward<T>(args)...);

    auto indexer1 = std::get<0>(tuple);
    auto indexer2 = std::get<1>(tuple);
    auto indexer3 = std::get<2>(tuple);
    auto indexer4 = std::get<3>(tuple);
    // etc
}

如果您的索引器访问连续内存,您可以使用GSL's span而不是索引器返回的类型T(或借用这个想法并编写自己的内容):

 template <typename T>
 void foo(span<T> indexer1, span<T> indexer2, span<T> indexer3, span<T> indexer4)
 {
 }