如何将三个函数转换为一个通用函数?

时间:2014-06-21 11:01:38

标签: c++ templates generics

我在下面的示例中有三个getColors函数。

问题:如何将threee getcolors函数转换为一个泛型函数?

struct EcvColorMap{
    vector<Scalar> getColors(){
        vector<Scalar> result;
        //....
        return result;
    }
};
struct Scalar{
   int val[3];
};

    vector<Scalar> getColors(vector<Scalar> colors){
        return colors;
    }
    vector<Scalar> getColors(Scalar color){
        return{ color };
    }
    vector<Scalar> getColors(EcvColorMap color_map){
        return color_map.getColors();
    }

4 个答案:

答案 0 :(得分:4)

问题是:功能的主体是不同的,如果你试图制作一个通用的,其他部分专业化,完全专业化,如

template<typename T> vector<Scalar> getColors(T colors) {
    return {colors};
}

//template<typename T> vector<Scalar> getColors(vector<T> colors) { // Not really necessary - see list initialization
//  return colors;
//}

template<> vector<Scalar> getColors<EcvColorMap>(EcvColorMap colors) {
    return colors.getColors();
}

你仍然需要为三个不同的模板编写代码而根本没有任何收益(编译时优势还是代码重用?)。

我个人的建议:不要使用模板,因为它很酷,在实际需要时使用它们。在大型软件视图中,这是至关重要的。你发布的设计对我有意义。

答案 1 :(得分:2)

您无需转换这些功能,这一点非常明确。

您的三个功能具有不同的主体,因此您无法将它们放在单个模板功能中。您可以使用模板函数替换它们,并使用这些类型的特化,但它只会使它复杂化。

答案 2 :(得分:1)

正如Marco的回答所指出的,在这种情况下,你必须权衡使用模板的优缺点。

话虽如此,你可以检查一种典型的方法,使用特征;这通常是在您希望抽象出可能以不同方式发生的事情时完成的。所以你可以这样发送实际的 getter

template<typename T>
vector<Scalar> getColors(T colors)
{
    return getter<T>::get(colors); 
}

然后,您将为每个实体构建一些特征

template<typename T>
struct getter; // types not specified in your traits system will not work

template<>
struct getter<vector<Scalar>> {
    static vector<Scalar> get(vector<Scalar> colors) { 
        return colors; 
    }
};

template<>
struct getter<Scalar> {
    static vector<Scalar> get(Scalar color) { 
        return { color }; 
    }
};

template<>
struct getter<EcvColorMap> {
    static vector<Scalar> get(EcvColorMap color) { 
        return color_map.getColors(); 
    }
};

没有魔力,你仍然需要手动编写所有代码。 唯一的例子就是,如果你必须在更多的地方使用 getter ,那么你就可以随时写下:

template<typename T>
void FunctionN(T arg)
{
    auto val = getter<T>::get(arg); 
    // do stuff like printing etc
}

因此,越大的N越能从抽象出get操作中获得越多。类似地,set操作可以被分割等等。

答案 3 :(得分:0)

前两个函数使用Scalarvector<Scalar>类型,这两个函数都可用于构造函数vector<Scalar>。您可以将这些功能缩减为支持任何可转换为Scalarvector<Scalar>的类型的函数。

template <class T>
std::vector<Scalar> getColors(const T& data)
{
    return { data };
}

// Overloads do not need to be a template.
std::vector<Scalar> getColors(const EcvColorMap& data)
{
    return { data.getColors() };
}

要消除最终getColors函数(如果有意义),您可以在EcvColorMap中提供显式转换运算符。这样就可以将EcvColorMap的实例传递给上面显示的getColors版本。

struct EcvColorMap
{
    explicit operator std::vector<Scalar>() const
    {
        std::vector<Scalar> result;
        //....
        return result;
    }
};

通过以上两项更改,您现在可以针对问题中列出的所有类型调用getColors

std::vector<Scalar> colors;
Scalar color;
EcvColorMap colormap;

getColors(color);
getColors(colors);
getColors(colormap);

如果提供转换运算符是有意义的,则可以通过构造和赋值来消除getColors函数。

std::vector<Scalar> colors;
Scalar color;

// Construct
std::vector<Scalar> new_colors1{color};
std::vector<Scalar> new_colors2{colors};

// Assign.
std::vector<Scalar> new_colors;
new_colors = colors;
new_colors = { color };
new_colors = colormap.getColors();