在运行时选择班级成员的类型

时间:2018-09-07 10:49:41

标签: c++ class templates metaprogramming

我试图构建一个包含其他类作为成员的模块化类,用户可以在运行时指定这些类的类型。我尝试使用模板来实现,但是意识到这可能不是正确的方法。这是一个最小的工作示例:

#include <iostream>

// One of the modules. Code will consist of multiple of these modules.
template <class T, class U>
class Module1 {
public:
    T subModule1;
    U subModule2;
};

class Add {
public:
    double Apply(double a) {
        return a + x;
    }

private:
    double x = 2.5;
};

class Multiply {
public:
    double Apply(double a) {
        return a * pi;
    }

private:
    double pi = 3.14;
};

class Divide {
public:
    double Apply(double a) {
        return a / pi;
    }

private:
    double pi = 3.14;
};

int main(int argc, char* argv[])
{
    // User input to determine the used submodules
    // Here the user decides to use the Add and Multiply submodules.
    Module1<Add, Multiply> module1;

    std::cout << module1.subModule1.Apply(3) + module1.subModule2.Apply(2) << std::endl;
}

但是我该如何决定应该使用哪个子模块呢?例如,如果用户要使用Divide和Add,则必须将Module1创建为

Module1<Divide, Add> module1;

会有许多不同的子模块,因此不可能用if分支代码。我开始怀疑使用模板是否可行。您知道实现此目标的更好方法吗?请注意,该实现也应该非常高效。

3 个答案:

答案 0 :(得分:4)

模板用于编译时多态性,而您想要运行时多态性。

如果您有一组封闭的可能子模块,则可以使用std::variant。它基本上是类型安全的union

using SubmoduleVariant = std::variant<Add, Subtract, Multiply, Divide>;

class Module1 {
public:
    SubmoduleVariant subModule1;
    SubmoduleVariant subModule2;
};

// ...

Module1 m;

     if(userInput == 0) { m.subModule1 = Add{}; }
else if(userInput == 1) { m.subModule1 = Subtract{}; }
else if(userInput == 2) { m.subModule1 = Multiply{}; }
else if(userInput == 3) { m.subModule1 = Divide{}; }

如果您事先不知道可能的类型集,但是它们都遵循相同的接口,则可以使用virtual函数和基类。


如果您事先不知道可能的类型集合,并且它们不符合相同的接口,则可以使用std::any,它基本上是“任何类型的对象”的包装。

答案 1 :(得分:2)

使用简单的多态性。

wrong

答案 2 :(得分:0)

可能的解决方案是进行所有可能的组合,然后选择正确的组合:

import mysql.connector
conn = None

try:
    conn = mysql.connector.Connect(host="localhost", user="jump", password="secret")
    print('Connected to MySQL!')
except Exception as ex:
    print('cannot connect to MySQL : exception : ' + str(ex))

cursor = conn.cursor()
cursor.close()
print('terminating connection with MySQL')
conn.close()

甚至可以通过一些元编程来创建数组。

但是我认为简单的多态性(作为dan的答案)就足够了。