内联函数中的未定义引用问题,使用一元加号解决

4
我是一个有用的助手,可以翻译文本。
我遇到了一个启用c++11的奇怪的gcc 4.7问题:
当我想编译这个时:
constexpr unsigned int getDim(const int e){
        return (e==1)?  A::Set::Dimension :
            (
              (e==2)? B::Set::Dimension :

                (
                    (e==3)? C::Set::Dimension :
                    (
                       +D::Set::Dimension

                    )
                )
            );
 }

对于每个结构体A,B,C,D,定义了一个Set的typedef,相关的集合有一个int类型的Dimension,例如:

struct SetOne{
   static const int Dimension = 1;
}

struct A{
   typedef SetOne Set;
}

如果我不在D::Set::Dimension前面使用unary +,链接器会报错,抱怨找不到SetOne::Dimension的定义。

这是否与以下问题相同:Undefined reference to static class member

我无法提供最小化可重现示例,因为对于仅含有一个.cpp文件的示例,该问题已经消失。 (但是所有A、B、C、D的定义都在同一个头文件中)

有人知道可能出现什么问题吗?这很不直观:-)

观察2: 如果将+D::Set::Dimension替换为0,则可以编译成功,但为什么其他语句如A::Set::Dimension没有引起相同的链接错误呢?


1
是的,你之前回答问题的假设似乎是正确的。类声明中的 static const int Dimension = 1; 只是一个静态变量声明,而不是定义(尽管有初始化)。你应该在类声明外显式定义类的静态成员。 - Constructor
如果我在cpp文件中定义类声明外的静态成员,那么我就不能在模板函数“fSet::Dimension”中使用静态int,因为编译器需要看到常量表达式...?我该如何避免这种情况? - Gabriel
1
如果您只使用整数类型的静态变量进行此类用途,您可以在类内初始化它们,并在类之外创建它们的定义不需要任何初始化。初始化与定义不同。如果您可以使用C++11,还可以尝试使用constexpr关键字。 - Constructor
1个回答

8
在您正在构建的表达式中,三元表达式产生了一个左值(lvalue),这会导致静态常量的odr-use。一定义规则要求所有odr-used的静态成员都需要被定义(在单个翻译单元中提供定义),因此您需要提供定义。
那么为什么一元+可以解决问题呢?
一元+不会导致静态成员的odr-use,它只需要一个右值(rvalue),并且其结果也是另一个rvalue。这通过条件运算符级联到表达式的结果,因为一旦两个参数中有一个是rvalue,表达式的结果也将是rvalue。最终的结果是,单个+的效果是强制执行函数中使用的所有静态常量的左值转换为右值,并消除odr-uses。
如果用0替换+D::Set::Dimension,它将编译成功。同样,0是一个rvalue,并且具有上述一元+的相同效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接