【问题标题】:Could somebody explain the template resolution order rules to me?有人可以向我解释模板解析顺序规则吗?
【发布时间】:2011-05-01 15:42:12
【问题描述】:

好的,这里完整的伪代码。

template <typename T>
void fun(/*...*/)
{
    some_meta_typelist pushback T;
}

所以这个想法是,在任何时候实例化这个函数,它都会增长 some_meta_typelist 对象。如果这是跨边界完成的,是否可以保证在可能在 MPL::fold 函数中使用类型列表之前编译对这个模板构建机制的所有调用。何时对这些进行评估,您何时可以确定它们已完成?这是否应该仅限于编译单元并且永远不会跨越 .cpp 边界?是否有等效于调用带有静态变量的函数以确保在使用前已创建对象?

更新

我正在研究这样一种想法,即调用系统的对象将构建系统完成工作所需的类型列表。我的感觉是类型列表将完全取决于编译顺序,因此不是单个文件 CPP 之外的有效方法。我知道 MSVC 是按字母顺序编译的,或者至少以前是按字母顺序编译的,所以我可以将最终文件命名为 ZZZZ.cpp,最终我的意思是需要完全构建的类型列表的文件。这不是一个安全或兼容的解决方案。是这样吗?有解决办法吗?

谢谢大家

【问题讨论】:

  • 我可以回答之前的第二个问题:您使用的是什么折叠功能?我只知道 Boost 版本,它是一个结构。你能把我链接到文档吗?
  • 考虑到您可以根据 C++ 模板解析规则制作一本书,因此不要对全面的答案寄予厚望。

标签: c++ templates metaprogramming boost-mpl


【解决方案1】:

这里是模板实例化工作原理的简化版本(我将通过Boost documentation for fold 进行处理)。

假设您是一个 C++ 编译器(我们称您为 clang...这是一个非常酷的名字),并且您很高兴阅读 .cpp 文件以编译它。您会看到所有这些正常功能,例如 void foo()float magic(int x, double p)int main(int argc, char** argv)。然后,你会遇到这样的事情:

template <typename T>
struct is_fun
{
    typedef some_other_type<T> something_else;
    typedef typename something_else::value value;
}

这里,clang 说:酷,我知道这个名为is_fun 的结构,它是一个以单一类型作为参数的模板。此时,is_fun 是一个未初始化的模板。重要的是要注意它在这里没有编译任何东西。当clang 看到模板化的任何内容时,它会检查语法(在其能力范围内)并继续前进。没有办法在目标代码中发出未初始化的模板 - 它是纯 C++ 且未编译的。

后来,它出现并看到is_fun 在这样的语句中被使用:

typedef vector<long,float,short,double,float,long,long double> types;
typedef fold<
             types,
             int_<0>,
             if_< is_fun<_2>,next<_1>,_1 >
            >
        ::type number_of_fun;

现在,clang 很懒,只会说“好吧,number_of_fun 只是那个可怕东西的别名。”再一次,它没有任何事情。稍后在您的代码中,它会看到:

int foo()
{
    const int fun = number_of_fun::value;
    return fun;
}

现在,它已经对number_of_fun 模板做了一些事情。现在,模板参数将被填充值(因为使用number_of_fun::value 需要它)。 clang 将逐步完成所有 Boost 内容,最终以您的模板化 is_fun 结束。它需要的列表中的第一件事是long(这就是折叠向量的作用),因此它会创建一个基于 long 的新类型,并填充所有 Ts:

struct is_fun<long>
{
    typedef some_other_type<long> something_else;
    static const int value = typename something_else::value;
}

这种类型被编译,因为它已经被使用了。 C++模板的基本规则是:当你在编译过程中使用它时,它会被实例化,这意味着它会被编译。在运行时您不需要做任何特别的事情。

【讨论】:

  • typedef typename something_else::value value; 不应该是static const int value = something_else::value吗?
  • 这不是我想知道的运行时间。如果我不断将新值推送到类型列表中并在其他地方使用它,那么什么时候使用类型列表的规则与推送发生时的规则有关。换句话说,在我使用 typelist 之前,如何确保所有内容都已推入。
  • @Tavison:抱歉,我没有看到你的回复。确保所有内容都在类型列表中的唯一方法是让编译器在实例化模板之前能够查看将添加到其中的所有内容。
  • 我决定现在让用户创建类型列表。如果我这样做,我将不得不对其使用施加许多限制。
  • 我的 +1。 SO 评级系统臭名昭著的缺点是专家级问题的专家答案总是比新手级问题的答案定价低得多......
猜你喜欢
  • 1970-01-01
  • 2011-06-13
  • 2018-01-20
  • 2011-05-08
  • 2021-02-18
  • 2012-04-09
  • 1970-01-01
  • 2023-02-08
  • 2011-01-08
相关资源
最近更新 更多