让编译器最终选择要使用的类型

时间:2012-11-02 15:14:19

标签: c++ templates constructor

这个问题需要了解C ++模板元编程,因为它涉及(间接)表达模板。我间接地说,因为它不直接是关于表达模板的问题,而是涉及C ++类型的计算。如果您不知道那是什么,请不要回答这个问题。

为了避免在没有足够背景信息的情况下提出问题,请让我详细说明我要解决的一般问题,然后转到更具体的部分。

假设您有一个提供Integer的库,用户可以像int一样进行计算。 此外,可以从Integer构造int。就像:

Integer<int> i(2);

我的Integer类内部是一个类模板:

template<class T>
class Integer {
  // cut out
};

所以我可以在我喜欢的任何整数类型上定义它。

现在,在不更改API的情况下,我想更改库,如果Integer是从int构建的,则应该在内部用不同的类型表示,例如{{1} }。这样做的原因是我可以加快一些计算,因为知道IntegerLit的实例是从Integer创建的(可以将它作为int参数传递给函数而不是作为一般对象由基指针+单独的数据描述。这只是一个注释。)

int构造时,类型不同是至关重要的,因为我需要编译器根据是从int构造还是构建不同的代码路径不。我无法使用运行时数据标志执行此操作。 (原因很简单:编译器根据类型生成一个函数,它接受int或上面提到的更一般类型的对象。)

有了这个说我遇到了一个问题:当用途做这样的事情时:

int

此处Integer<int> a,b(2); a = b + b; 应为常规aInteger专用b。但是,我的问题是如何在C ++中表达这一点,因为用户可以自由地使用相同的类型IntegerLit来定义她的变量。

使类型具有多态性,即从Integer派生IntegerLit将不起作用。它看起来很好。但是,由于用户创建的Integer(基类)实例不起作用,因为它是基类,编译器会将其粘贴到表达式树中(这就是问题中涉及表达式模板的原因)。因此,两种情况之间不可能有任何区别。在这一点上做RTTI检查动态转换真的不是我想要的。

更有希望似乎是在类型中添加文字模板参数Integer,说明它是否是从bool lit构建的。关键是不要为一个非文字指定转换规则,而是为另一个案例指定转换规则。

然而,我无法让它发挥作用。如果不是从int构造,则以下代码仅编译(GCC 4.7 C ++ 11)。否则会失败,因为未使用int指定整数作为true的值。因此编译器会搜索没有转换规则的默认实现。在从lit构建时,不能更改API并要求编写Integer<int,true>

int

我开始想知道C ++是否可以这样做。

C ++ 11可能有新功能可以提供帮助吗?

3 个答案:

答案 0 :(得分:5)

不,这不是C ++的工作原理。如果您将b定义为Integer b,那么它就是Integer。无论后来用于初始化b的表达式如何,这都适用。

另外,请考虑以下事项:extern Integer b;。在其他地方有一个初始化b的表达式,但编译器仍然必须在此处弄清楚b的类型。 (不是“会有”,而是“有”)。

答案 1 :(得分:3)

无论如何,你无法做到这一点。 但是使用“自动”你可以接近。

// The default case
Integer<int> MakeInt()
{
    return Integer<int>();
}

// The generic case
template <class T>
Integer<T> MakeInt(T n)
{
    return Integer<T>(n);
}

// And specific to "int"
Integer<IntegerLit> MakeInt(int n)
{
    return Integer<IntegerLit>(n);
}

auto a = MakeInt();
auto b = MakeInt(2);
auto c = MakeInt('c');
auto d = MakeInt(2.5);

答案 2 :(得分:1)

你做不到。一旦你说变量是Integer<int>这是变量的类型。你可以做的是让Integer的底层代表根据使用的构造函数而变化,如下所示:

template<class T>
class Integer {
  // cut out
    Integer() : rep_(IntRep()) {}
    explicit Integer(int val) : rep_(IntLitRep(val)) {}

private:
    boost::variant<IntRep, IntLitRep> rep_;
};

然后,您可以轻松确定哪个变体版本处于活动状态,并在需要时使用不同的代码路径。

编辑:在这种情况下,即使Integer的类型相同,您也可以轻松地使用模板函数使其看起来表现为两种不同的类型(因为代码更改了有效类型)。 / p>