c++ - 在运行时选择合适的专用模板

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

我正在使用第 3 方库中的一个类,它看起来像,

template <typename A = DefaultT, typename B = DefaultT, typename C = DefaultT, typename D = DefaultT, typename E = DefaultT, typename F = DefaultT>
class Vertex {};

我想在运行时根据条件使用此类的部分特化,例如,

class MyA {};
class MyB {};
class MyC {};
class MyD {};
bool useA, useB, useC, useD; //these booleans change at runtime
// I want to specialize Vertex depending on the above booleans
// The below line shouldn't compile, this is just to give an idea
typedef typename Vertex <useA ? MyA : DefaultT,  useB ? MyB : DefaultT,  
                         useC ? MyC : DefaultT,  useD ? MyD : DefaultT> MyVertex;

我想有条件地选择我想要特化的模板参数。 我不确定这个问题是否有一个术语,我怀疑它是多重调度的一种。

一个简单的方法是编写 15 (2^4 -1) 个类,例如,

typedef typename Vertex <MyA> MyVertexWithA;
typedef typename Vertex <DefaultT, MyB> MyVertexWithB;
typedef typename Vertex <MyA, MyB> MyVertexWithAB; //and so on...until
typedef typename Vertex <MyA, MyB, MyC, MyD> MyVertexWithABCD;

问题变得更加复杂,因为我必须使用一个使用专门顶点类的“网格”类

template <typename VertexClass, typename Others>
class Mesh {};

现在,如果我继续编写 15 个类,那么我将不得不为每种不同的网格类型再编写 15 行。并且在使用 Mesh 类的地方变得越来越复杂。

我坚信这必须由我或编译器来完成。我的问题:

  1. 我想知道是否有办法让编译器为我完成这项工作?
  2. C++11 是否有更好的机制来处理这种情况? 谢谢。

最佳答案

答案是否定的。如果条件在运行时发生变化,那么您不能根据这些条件专门化/实例化模板,它们需要是常量表达式(毕竟,编译器在编译器时执行此工作,程序开始运行之前,所以使用运行时表达式是不行的)。如果它们是在编译时确定的,那么您可以结合使用 constexpr 技巧和 std::conditional .

正如@Karloy Horvath 提到的,您还可以执行称为标签调度的操作,类似于下面的示例:

#include <iostream>

struct tag_yes{};
struct tag_no{};

template <typename T> void f_tag();

template <> 
void f_tag<tag_yes>() // specializations 
{
    std::cout << "YES" << std::endl;
}

template <> 
void f_tag<tag_no>()
{
    std::cout << "NO" << std::endl;
}

void f(bool condition)
{
    if(condition)
        f_tag<tag_yes>(); // call the YES specialization
    else
        f_tag<tag_no>(); // call the NO specialization
}

int main()
{
    bool condition = true;
    f(condition); // dispatch to the "right" template function
}

或者,您甚至可以推导出标签(这就是标准 C++ 算法与各种迭代器类型一起工作的方式)

#include <iostream>
#include <type_traits>

struct Foo
{
    using tag = std::true_type;
};

struct Bar
{
    using tag = std::false_type;
};

template <typename T> void f_tag();

template <> 
void f_tag<std::true_type>() // specializations 
{
    std::cout << "YES" << std::endl;
}

template <> 
void f_tag<std::false_type>()
{
    std::cout << "NO" << std::endl;
}

template <typename T>
void f(const T&)
{
        f_tag<typename T::tag>(); // dispatch the call
}

int main()
{
    Foo foo;
    Bar bar;

    f(foo); // dispatch to f_tag<std::false_type>
    f(bar); // dispatch to f_tag<std::true_type>
}

但是,在您的情况下,通过工厂方法和通用虚拟接口(interface),多态性可能是可行的方法。

关于c++ - 在运行时选择合适的专用模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30169433/

相关文章:

c++ - Eigen 3 并根据模板参数重载新运算符以确保正确对齐

c++ - 如何将 std::getline 转换为模板类型?

c++11 - 使用简单的运算符<对std::set<my_class>进行Initializer_list初始化。 gcc+/标准库中的错误?

c++ - std::thread - 如何让主线程继续运行而子线程分支

c++ - 为什么类型推导在(非指针)函数类型上失败

c++ - FBX SDK 导出为旧的 fbx 文件格式

c++ - 尽管设置了路径,但 g++/Eclipse 找不到包含文件

c++ - 如何从继承的模板访问 typedef

c++ - 为什么对默认参数发出警告?

c++ - 将 std::string 转换为 char *