指向功能和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

上一篇: pointer to function and ODR

下一篇: Apache flume twitter agent not streaming data