在运行时指定模板参数

Dan*_*vil 31 c++ templates

考虑以下模板类

class MyClassInterface {
public:
  virtual double foo(double) = 0;
}

class MyClass<int P1, int P2, int P3>
: public MyClassInterface {
public:
  double foo(double a) {
    // complex computation dependent on P1, P2, P3
  }
  // more methods and fields (dependent on P1, P2, P3)
}
Run Code Online (Sandbox Code Playgroud)

模板参数P1,P2,P3是在限制范围就像从0一些固定值n固定在编译时.

现在我想建立一个像"工厂"的方法

MyClassInterface* Factor(int p1, int p2, int p3) {
  return new MyClass<p1,p2,p3>(); // <- how to do this?
}
Run Code Online (Sandbox Code Playgroud)

问题是如何在模板参数仅在运行时知道时如何实现模板类的构造.对于具有非常大的域(如双)的模板参数,同样可能吗?如果可能的解决方案可扩展到使用更多模板参数,请另请考虑.

Bil*_*nch 19

这是你可以做的:

MyClassInterface* Factor(int p1, int p2, int p3) {
  if (p1 == 0 && p2 == 0 && p3 == 0)
    return new MyClass<0,0,0>();
  if (p1 == 0 && p2 == 0 && p3 == 1)
    return new MyClass<0,0,1>();
  etc;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这甚至无法远程扩展到浮点值.它仅扩展到已知的离散值列表.


我之前也使用过这段代码做一些模板自动生成:

#include <boost/preprocessor.hpp>

#define RANGE ((0)(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12))
#define MACRO(r, p) \
    if (BOOST_PP_SEQ_ELEM(0, p) == var1 && BOOST_PP_SEQ_ELEM(1, p) == var2 && BOOST_PP_SEQ_ELEM(2, p) == var3 && BOOST_PP_SEQ_ELEM(3, p) == var4) \
        actual_foo = foo<BOOST_PP_TUPLE_REM_CTOR(4, BOOST_PP_SEQ_TO_TUPLE(p))>;
BOOST_PP_SEQ_FOR_EACH_PRODUCT(MACRO, RANGE RANGE RANGE RANGE)
#undef MACRO
#undef RANGE
Run Code Online (Sandbox Code Playgroud)

编译器生成如下所示的输出:

if (0 == var1 && 0 == var2 && 0 == var3 && 0 == var4) actual_foo = foo<0, 0, 0, 0>;
if (0 == var1 && 0 == var2 && 0 == var3 && 1 == var4) actual_foo = foo<0, 0, 0, 1>;
if (0 == var1 && 0 == var2 && 0 == var3 && 2 == var4) actual_foo = foo<0, 0, 0, 2>;
if (0 == var1 && 0 == var2 && 0 == var3 && 3 == var4) actual_foo = foo<0, 0, 0, 3>;
if (0 == var1 && 0 == var2 && 0 == var3 && 4 == var4) actual_foo = foo<0, 0, 0, 4>; 
if (0 == var1 && 0 == var2 && 0 == var3 && 5 == var4) actual_foo = foo<0, 0, 0, 5>;
if (0 == var1 && 0 == var2 && 0 == var3 && 6 == var4) actual_foo = foo<0, 0, 0, 6>;
if (0 == var1 && 0 == var2 && 0 == var3 && 7 == var4) actual_foo = foo<0, 0, 0, 7>;
if (0 == var1 && 0 == var2 && 0 == var3 && 8 == var4) actual_foo = foo<0, 0, 0, 8>;
etc...
Run Code Online (Sandbox Code Playgroud)

此外,请注意,使用此方法,使用4个变量,每个变量超过13个值,您将使编译器实例化此函数的28561个副本.如果您的n为50,并且您仍然有4个选项,那么您将实例化6250000个函数.这可以使SLOW编译.

  • "这可以实现SLOW编译" - 更不用说预处理的大小接近半千兆字节,并且如果您找到了可以应对的编译器,则会产生大量的可执行大小. (6认同)
  • 由于代码大小和指令缓存未命中,编译速度慢,**和**运行时可能很慢,从而首先打败了编译时微优化的重点.这似乎很重要,值得注意. (3认同)

jon*_*son 11

如果宏不是你的东西那么你也可以使用模板生成if-then-else的:

#include <stdexcept>
#include <iostream>

const unsigned int END_VAL = 10;

class MyClassInterface
{
public:
    virtual double foo (double) = 0;
};

template<int P1, int P2, int P3>
class MyClass : public MyClassInterface
{
public:
    double foo (double a)
    {
        return P1 * 100 + P2 * 10 + P3 + a;
    }
};

struct ThrowError
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        throw std::runtime_error ("Could not create MyClass");
    }
};

template<int DEPTH = 0, int N1 = 0, int N2 = 0, int N3 = 0>
struct Factory : ThrowError {};

template<int N2, int N3>
struct Factory<0, END_VAL, N2, N3> : ThrowError {};

template<int N1, int N3>
struct Factory<1, N1, END_VAL, N3> : ThrowError {};

template<int N1, int N2>
struct Factory<2, N1, N2, END_VAL> : ThrowError {};

template<int N1, int N2, int N3>
struct Factory<0, N1, N2, N3>
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        if (c1 == N1)
        {
            return Factory<1, N1, 0, 0>::create (c1, c2, c3);
        }
        else
            return Factory<0, N1 + 1, N2, N3>::create (c1, c2, c3);
    }
};

template<int N1, int N2, int N3>
struct Factory<1, N1, N2, N3>
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        if (c2 == N2)
        {
            return Factory<2, N1, N2, 0>::create (c1, c2, c3);
        }
        else
            return Factory<1, N1, N2 + 1, N3>::create (c1, c2, c3);
    }
};

template<int N1, int N2, int N3>
struct Factory<2, N1, N2, N3>
{
    static inline MyClassInterface* create (int c1, int c2, int c3)
    {
        if (c3 == N3)
        {
            return new MyClass<N1, N2, N3> ();
        }
        else
            return Factory<2, N1, N2, N3 + 1>::create (c1, c2, c3);
    }
};

MyClassInterface* factory (int c1, int c2, int c3)
{
    return Factory<>::create (c1, c2, c3);
}
Run Code Online (Sandbox Code Playgroud)

由于测试是嵌套的,因此它应该比sharth的宏解决方案更有效.

您可以通过添加更多深度案例将其扩展到更多参数.


Ark*_*nez 8

这是不可能的,模板在编译时实例化.
当你有一个可执行文件时,你只有类(这些模板的特定实例),不再有模板.

如果您在编译时不知道值,则无法获得这些值的模板.

  • 如果不构造所有可能的情况并进行运行时切换,则无法“仅在运行时知道模板参数时实现模板类的构造”。 (2认同)