3

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

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

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

Integer<int> i(2);

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

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

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

现在在不更改 API 的情况下,我想以一种方式更改库,即 ifInteger是从 an 构造的,int它应该在内部由不同的类型表示,比如IntegerLit. 这样做的原因是我可以加快一些计算,因为我知道一个实例Integer是从一个创建的int(可以将它作为int参数传递给一个函数,而不是作为一个由基指针 + 单独数据描述的通用对象。这就像一个评论。)

从 an 构造时类型不同是很重要的,int因为我需要编译器根据是否从 an 构造来占用不同的代码路径int。我不能用运行时数据标志来做到这一点。(简而言之:编译器生成一个函数,该函数根据类型采用一个int或更通用的对象类型。)

话虽如此,我遇到了一个问题:当使用做这样的事情时:

Integer<int> a,b(2);

a = b + b;

这里a应该是一般的Integerb专门的IntegerLit。然而,我的问题是如何在 C++ 中表达这一点,因为用户可以自由地使用相同的类型Integer来定义她的变量。

使类型多态,即派生IntegerLitInteger将不起作用。暂时看起来还不错。但是,由于用户创建了Integer(基类)的实例,因为它是基类,所以编译器会粘在表达式树中(这就是问题中涉及表达式模板的原因)。因此,这两种情况再次无法区分。在这一点上,做一个 RTTI 检查一个动态演员真的不是我想要的。

更有希望的似乎是将文字模板参数添加bool lit到类型中,说明它是否由 a 构造而成int。关键是不要为一个不是文字的情况指定转换规则,而是为另一种情况指定它。

但是,我无法让它发挥作用。如果不是从int. 否则它会失败,因为没有将 Integer 指定true为 的值lit。所以编译器搜索没有转换规则的默认实现。Integer<int,true>int. _

template<class T,bool lit=false>
class Integer
{
public:
  Integer() {
    std::cout << __PRETTY_FUNCTION__ << "\n";
  }
  T F;
};

template<>
template<class T>
class Integer<T,true>
{
public:
  Integer(int i) {
    std::cout << __PRETTY_FUNCTION__ << "\n";
  }
  T F;
};

我开始想知道 C++ 是否可以实现这样的事情。

C++11 的一个新特性是否可以在这里提供帮助?

4

3 回答 3

5

不,这不是 C++ 的工作方式。如果你定义bInteger b,那么它就是一个Integer。无论随后用于初始化的表达式如何,这都适用b

此外,请考虑以下事项:extern Integer b;. 在其他地方有一个初始化 的表达式b,但编译器仍然必须在这里找出类型b有什么。(不是“将有”,而是“有”)。

于 2012-11-02T15:18:57.897 回答
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);
于 2012-11-02T15:34:48.293 回答
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_;
};

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

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

于 2012-11-02T16:04:49.783 回答