调用具有不同签名的其他构造函数的构造函数

时间:2017-08-07 06:29:20

标签: c++11

假设我有一个名为 Mesh 的类,在Mesh中我有不同的静态方法,如

 static Mesh makeTriangle(...)

有一些参数。然后我也有:

  • static Mesh makeBox(...):参数类型和数量与makeTriangle不同,

  • static Mesh makeSphere(...)完全与makeTriangle相同的参数类型和数量等等

如何创建一个构造函数,它将const std::string &name作为它的第一个参数和可变数量的参数,我可以传递给创建Mesh对象的右边“make”方法?
在c ++ 11中这可能吗?

我尝试使用像这样的变量模板

template<typename... Params>
Mesh(const std::string &name, Params&&... parameters)
    : Mesh(init(name, std::forward<Params>(parameters)...)) {}

但是在init方法的某些时候我必须做类似

的事情
template<typename... Params>
static Mesh init(const std::string &name, Params&&... parameters) { 
    if(name == "box") return makeBox(std::forward<Params>(parameters)...)
    if(name == "sphere") return makeSphere(std::forward<Params>(parameters)...)
    /* and so on */
}

编译器将拒绝编译,因为参数包可能与某些make方法参数不匹配。我不能把它放在一个带字符串并输出函数指针的映射中,因为提到的make方法有不同的签名 那么我怎样才能在c ++ 11中做到这一点?

编辑
我认为使用继承来为每个不同的形状创建子类将不是最佳选择,因为所有Mesh对象本质上都是空间中的点列表,它们都是对象类,它们的唯一区别在于它们的方式构造

2 个答案:

答案 0 :(得分:1)

您应该使用标记,例如标记类:

,而不是使用字符串
struct box {};
struct sphere {};

template<class Tag, typename... Params>
 static Mesh init(Tag, Params&&... parameters) { 
     if constexpr (std::is_same<Tag, box>::value) return makeBox(std::forward<Params>(parameters)...)
     else if constexpr (std::is_same<Tag, sphere>::value) return makeSphere(std::forward<Params>(parameters)...)
    /* and so on */
}

然后您的用户会将构造函数称为例如Mesh{box{}, a, b, c}

作为标记类的替代方法,您还可以使用枚举和integral_constant

enum class MeshName { Box, Sphere, ... };

template<class Name, typename... Params>
 static Mesh init(std::integral_constant<MeshName, Name>, Params&&... parameters) { 
     if constexpr (Name == MeshName::Box) return makeBox(std::forward<Params>(parameters)...)
     else if constexpr (Name == MeshName::Sphere) return makeSphere(std::forward<Params>(parameters)...)
    /* and so on */
}

如果您的name参数必须是字符串,那么您唯一的选择是将参数检查推迟到运行时并发出运行时错误:

template<typename... Params>
static Mesh init(const std::string &name, Params&&... parameters) { 
    if(name == "box")
        if constexpr (std::is_invocable<decltype(makeBox), Params...>::value)
            return makeBox(std::forward<Params>(parameters)...)
        else
            throw std::invalid_argument("Incorrect arguments for makeBox");
    if(name == "sphere")
        if constexpr (std::is_invocable<decltype(makeSphere), Params...>::value)
            return makeSphere(std::forward<Params>(parameters)...)
        else
            throw std::invalid_argument("Incorrect arguments for makeSphere");
    /* and so on */
}

答案 1 :(得分:0)

你已经错过了整个继承点。这一点基本上就是你将所有常见内容保存在Shape(如位置)中,并将所有内容保持在子类中。

首先,在构建三角形和矩形等多边形时,类似于半径(对于基于π的形状(如圆和球)至关重要) no

在伪代码中,你应该做的是:

class shape:
    float x_coord
    float y_coord

class rectangle: inherits shape
    float width
    float height

class circle: inherits shape
    float radius

然后构建具体形状而不是更抽象的形状。这些具体的形状,即shape的子类应该能够使用所有常见的东西以及它们在继承过程中添加的东西。