让编译器做出最终选择,要使用哪种类型

Let the compiler make the final choice which type to use

本文关键字:类型 种类 选择 编译器      更新时间:2023-10-16

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

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

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

Integer<int> i(2);

内部我的Integer类是类模板:

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

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

现在没有更改API,我想以一种从int构造的Integer来更改库,应该在内部以其他类型表示IntegerLit。原因是我知道Integer的实例是从int创建的(可以将其作为int参数传递到函数,而不是基本指针 单独的数据描述的一般对象。就像评论一样。)

int构造时,类型是不同的,因为我需要编译器根据int构造是否构建编译器来操作不同的代码路径。我无法使用运行时数据标志来执行此操作。(简而言之:编译器生成一个函数,该函数取决于int或上述更通用的对象类型。)

这样说我会遇到一个问题:当用途这样做时:

Integer<int> a,b(2);
a = b + b;

这里a应该是一般Integerb专用IntegerLit。但是,我的问题是如何在用户免费使用相同类型的Integer定义她的变量时表达C 。

制作类型的多态性,即从Integer派生IntegerLit行不通。片刻看起来不错。但是,由于用户创建了Integer(基类)的实例,因为它是编译器粘在表达树中的基类,因此无法使用(这就是为什么表达模板都参与问题的原因)。因此,在两种情况之间不可能区分。做RTTI检查LA动态演员真的不是我想要的。

更有前途的似乎是在类型上添加了字面模板参数bool lit,说明它是由int构造的。关键是不要为一个不是字面的转换规则指定转换规则,而是为另一种情况指定。

但是,我无法做到这一点。如果不从int构造,则仅编译以下代码(GCC 4.7 C 11)。否则,它会失败,因为整数未用true指定为lit的值。因此,编译器搜索没有转换规则的默认实现。从int构造时,它不是更改API的选项,需要编写Integer<int,true>

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的新功能可以在这里提供帮助?

不,这不是C 的工作方式。如果将b定义为Integer b,则是Integer。这适用于随后用于初始化b的表达式。

另外,请考虑以下内容:extern Integer b;。在其他地方有一个表达式,可以初始化b,但是编译器仍然必须在这里弄清楚哪种类型b具有。(不是"有",而是"有")。

您完全无法做到这一点。但是使用"自动"可以接近。

// 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);

您不能做到这一点。一旦您说一个变量是Integer<int>,即变量类型。您的 can 是使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的类型相同,您也可以轻松地使用模板函数使其看起来像是两种单独的类型(因为REP更改有效类型)。

<</p>