C++ 指向函数和ODR的指针

C++ 指向函数和ODR的指针,c++,c++11,function-pointers,function-templates,one-definition-rule,C++,C++11,Function Pointers,Function Templates,One Definition Rule,关于ODR有很多问题,但我找不到我想要的,所以如果这是重复的或者标题不合适,我深表歉意 考虑以下几点: struct t {t(*id)();}; template<typename T> t type() {return {type<T>};} 在两个单位中取相同的值(类型t(*)(),因此用作类型t的唯一标识符 该值是函数类型的地址,因此问题是程序中唯一的函数类型是否由。iso 3.2/3规定: 每个程序应包含该程序中使用的每个非内联函数或变量的一个定义 其中3.

关于ODR有很多问题,但我找不到我想要的,所以如果这是重复的或者标题不合适,我深表歉意

考虑以下几点:

struct t {t(*id)();};

template<typename T>
t type() {return {type<T>};}
在两个单位中取相同的值(类型
t(*)(
),因此用作类型
t
的唯一标识符

该值是函数
类型
的地址,因此问题是程序中唯一的函数
类型
是否由。iso 3.2/3规定:

每个程序应包含该程序中使用的每个非内联函数或变量的一个定义

其中3.2/2

除非[…],否则将使用odr的非重载函数,其名称将显示为可能的求值表达式或[…]

我假设一个函数是非内联的,如果它的地址被占用(尽管我在标准中找不到)

iso 3.2/5列出了许多例外情况,但对函数的唯一引用是

具有外部链接的内联函数[…],非静态函数模板[…],类模板的成员函数,或未指定某些模板参数的模板专用化[…]

这里的情况似乎都不是这样

一个可验证的示例将包含多个文件。事实上,一个声称失败的例子由给出,尽管在我的案例中它没有失败(我不认为这是任何形式的“担保”)


那么,这是否有效呢?

因此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.
}
static inti;
//这是你的模板。
模板
void foo(){
i、 //与上面的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;    
}
static inti;
//这是你的模板。您通常可以有多个
//它的定义完全相同。
模板
void foo(){
//哦,匹配不同的实体。您没有满足要求。
//所有的赌注都输光了。
我
}
我知道Linux通过弱符号支持多个定义。事实上,在Linux上,幸运的例子正是因为这个原因失败了。我在他的回答中留下了一条评论,要求提供平台。在链接时,链接器将丢弃弱符号的所有实例,只有一个除外。显然,如果实例实际上不一样,那就不好了。但3.2/5中的这些要求旨在确保实例实际上都是相同的,因此链接器只能保留一个实例


增编:迪特尔·勒金现在说他有一个编译问题,事实上他并没有失败。不过,如果熟悉Windows DLL内部结构的人可以在此处评论Visual Studio如何处理此问题,那就太好了。

这几乎是同一个问题:(但我不确定这里给出的答案是否完全准确)。@jogojapan确实,这个问题实际上是一样的,谢谢。但我不能通过看答案就说情况对我来说很清楚。
type
是“非静态函数模板”吗?那么3.2/5适用吗?这不是一个函数模板吗?它不是静态的,所以它不是“非静态函数模板”吗?如果是静态函数模板,则有内部链接,因此不同TU中同名函数模板之间的内容不要求相等。同意dyp。我不明白为什么它不属于非静态函数模板异常。但是,如果其中有一个静态局部变量,该怎么办?标准不要求它是唯一的吗?请看:。谢谢,我希望你的阅读是正确的。如果能达成共识,我会更高兴。您的示例不是关于如何使用代码,而是关于如何定义代码。我对
类型的定义
在函数体中仅作为一个符号。这并不违反要求,是吗?技术上,是的,这取决于你如何定义它。我应该改变我的措辞,过一会儿我会的。请注意,TU中包含的每个模板都是一个单独的定义,因此理论上,您可能无意中将其包含在导致生成的定义不满足要求的方式中。但是,在你的例子中,这似乎是不可能的,除非TU做了真正恶意的事情,比如使用宏、定义专门化等等。此外,我在上面的回答中添加了一些关于Lucking示例的内容。
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;    
}