指向功能和ODR的指针
在ODR上有太多的问题,但我找不到我要找的东西,所以如果这是重复的或标题不合适的话,请致歉。
考虑以下:
struct t {t(*id)();};
template<typename T>
t type() {return {type<T>};}
这是我试图为每种类型定义唯一标识符的过度简化,希望这些标识符在不同的编译单元中保持唯一。
特别是,给定一个像std::string
这样的具体类型T
,并且假设两个不同的编译单元在头文件中包含上面的代码,我想要表达式
type<T>().id
在两个单元中采用相同的值(类型t(*)()
),因此作为类型T
的唯一标识符。
该值是函数type<T>
的地址,所以问题在于程序中的唯一函数type<T>
是否由单定义规则保证。 iso 3.2 / 3说
每个程序都应该包含每个非内联函数或该程序中odr使用的变量的一个定义。
哪里乘3.2 / 2
一个非重载函数的名称显示为潜在评估的表达式或[...],是odr使用的,除非[...]
我假设一个函数是非内联的,如果它的地址被采用的话(尽管我在标准中找不到那个函数)。
ISO 3.2 / 5列出了一些例外情况,但是对函数的唯一引用是
内联函数,外部链接,非静态函数模板,类模板的成员函数或模板专门化,某些模板参数未指定[...]
在这里并没有出现这种情况。
一个可验证的例子将需要多个文件。 事实上,一个声称失败的例子是DieterLücking给出的,尽管它并没有在我的案例中失败(我不认为这是“担保”的任何形式)。
那么,这是否会起作用?
所以3.2 / 5实际上似乎是非常强大的支持。 首先要注意的是,定义是源代码构造,而不是对象代码构造,尽管显然存在非常密切的关系。 3.2 / 5是说可以有多个非静态函数模板的定义,而且在这种情况下它必须表现得好像只有一个定义一样。 如果一个函数在不同的翻译单元中有不同的地址,那么至少在我的阅读中,这并不像只有一个定义一样。
这是特别真实的,因为函数指针可以作为非类型模板参数传递。 所有翻译单位必须保持不变并且必须保持一致。 例如,字符串文字不能完全是这样一个参数,因为它的地址因翻译单位而异。
是否满足所有要求将完全取决于多个定义的上下文,因为它们处理诸如名称解析等事情。但是,它们都是“普通”的要求,它们是“当然”类型。 例如,违反它会是这样的:
file1.cpp
static int i;
// This is your template.
template <typename T>
void foo() {
i; // Matches the above i.
}
file2.cpp
static int i;
// This is your template. You are normally allowed to have multiple
// identical definitions of it.
template <typename T>
void foo() {
// Oops, matches a different entity. You didn't satisfy the requirements.
// All bets are off.
i;
}
我知道Linux中通过弱符号支持多种定义。 实际上,在Linux上,Lucking示例并未因此而失败。 我在他的回答中留下了评论,要求提供平台。 在链接时,链接器将丢弃除一个以外的弱符号的所有实例。 显然,如果这些实例并不相同,那就太糟糕了。 但3.2 / 5中的这些要求旨在确保实例完全相同,因此链接程序只能保留一个。
附录:Dieter Lucking现在说他有一个汇编问题,而且事实上他并没有失败。 不过,如果熟悉Windows DLL内部的人可以在这里发表评论,那么Visual Studio如何处理这个问题会很好。
链接地址: http://www.djcxy.com/p/78725.html