考虑以下:
struct t {t(*id)();}; template<typename T> t type() {return {type<T>};}
这是我对定义unique identifier per type的尝试的过度简化,希望在不同的编译单元中保持唯一.
特别是,给定一个类似于std :: string的具体类型T,并假设两个不同的编译单元在头文件中包含上面的代码,我想表达
type<T>().id
在两个单元中采用相同的值(类型为t(*)()),因此用作类型T的唯一标识符.
该值是函数类型< T>的地址,因此问题是唯一的函数类型< T>是否为0.在程序中由one-definition rule保证.iso 3.2 / 3说
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program.
其中3.2 / 2
A non-overloaded function whose name appears as a potentially-evaluated expression or […],is odr-used,unless […]
我假设一个函数是非内联的,如果它的地址被采用(虽然我在标准中找不到).
iso 3.2 / 5列出了许多例外,但对函数的唯一引用是
inline function with external linkage,[…],non-static function template,member function of a class template,or template specialization for which some template parameters are not specified […]
似乎没有一个在这里的情况.
一个可验证的示例将需要多个文件.事实上,一个声称失败的例子是在Dieter Lücking给出的,虽然它在我的情况下没有失败(我不采取任何形式的“保证”).
那么,这是否有效?
解决方法
这尤其正确,因为函数指针可以作为非类型模板参数传递.这些参数必须是常量,并且对于所有翻译单元必须相同.例如,字符串文字不能精确地成为这样的参数,因为它的地址因翻译单元而异.
是否满足所有要求将完全取决于多个定义的上下文,因为它们处理诸如名称解析等事情.但是,它们都是“普通的”要求. “当然”类型.例如,违反它将是这样的:
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中的那些要求旨在确保实例实际上完全相同,因此链接器只能保留一个.
ADDENDUM:Dieter Lucking现在说他有编译问题,事实上他并没有失败.如果熟悉Windows DLL内部的人可以在这里发表评论,那将是很好的,关于Visual Studio如何处理这个问题.