2017-01-16 66 views
1

替换为static const成员我跨代码来这样从程序员本人高度方面:优势与静态成员函数

class BigClass { 
    using MyId = uint32_t; 
    static constexpr MyId INVALID_ID() { return std::numeric_limits<MyId>::max();}; 
    class SmallClass { 
    /* Constructor, etc. */ 
    MyId id = INVALID_ID(); /* Default value */ 
    }; 
}; 

是否有任何明显的优势,定义INVALID_ID()为函数而不是作为一个静态常量变量?

问题static constexpr variable vs function与我的问题完全相同(我使用uint32_t作为示例,但我发现其他类型的问题也很有趣)。但是,我对这个问题的答案并不满意。在阅读了这里的一些答案之后,我相信使用函数比使用简单模板更有优势。

+0

那么,因为它不是一个静态成员变量,它不需要在类之外定义。 – NathanOliver

+1

@NathanOliver在使用ODR之前,IIRC静态常量不需要定义。 – Quentin

+0

@Quentin Typo固定。他们可能会在这种情况下使用它。 – NathanOliver

回答

1

其中一个原因是,在这种形式下,不需要在类之外定义静态成员,在类中实现头的情况下,这是不可取的。

的第二个理由是可扩展性,你有一天想你的无效标识做在其初始化其他一些constexpr逻辑,除了调用诸如最大一个constexpr功能

+0

那么,因为这是一个整型常量,所以无论如何都不需要在类之外定义它。显然,它不应该被用作左值,只要它不被用作左值,就不需要定义。 – AnT

+0

在我看来,这仍然是一个好习惯 – ZivS

+0

引用相反,如果静态常量仅用作右值,那么*不定义它是一个好习惯 - 它可以防止滥用它作为左值。使定义成为可选是C++规范中一个重要而且期待已久的补充。 – AnT

-1

我没有看到任何优势。我宁愿将INVALID_ID声明为一个const(constexpr)而不是函数,因为函数调用会让读者想知道正在进行什么样的计算。

+0

类似的问题被问到这里:https://stackoverflow.com/questions/16287776/static-constexpr-variable-vs-function?noredirect=1&lq=1 –

+0

声明是一个constexpr函数其中有零动态计算,而不是在任何其他声明看到一个constexpr任何东西 – ZivS

1

这与线程安全和静态初始化命令失败有关。如果在单独的翻译单元中定义了两个相互依赖的静态变量(一个需要另一个翻译单元的值来构建自身),则无法保证它们将被初始化的顺序。

使用包装函数和C++ 11保证编译器将围绕其初始化放置必要的线程锁,函数local static将对该函数进行并发调用,等待变量在继续执行之前进行初始化。

+0

你应该改变忘记做*这必须忘记与线程安全和静态初始化顺序失败*? – NathanOliver

+0

是的,电话键盘没有在猜测我想输入什么时得到了更好的... – rubenvb

+0

好的,我只是想检查一下你是否捣碎了不同的句子, – NathanOliver

1

一个问题人们试图通过更换类的静态解决具有函数的常量成员是链接器错误。

例如:

struct A { 
    static constexpr int a = 1; 
}; 

void foo(int const&); 

foo(A::a); // Linker error: A::a. 

正确的解决方案是不拿指针或引用A::a(如果提供的A::a的外的线定义是不希望的):

void foo(int); 
+0

你可以拿指针。只需要定义'A :: a'。 –

+0

@NO_NAME定义'A :: a'可能不合需要。 –

2

除了简单的编码用法之外,我只能看到一个真正的区别:静态常量变量只有在使用odr时才需要定义(用于以ref为例的函数中...)。问题是,如果这个规则不被遵守,你会得到一个链接时间错误,程序员可能会浪费时间搜索问题的真正原因。

当您以这种方式使用某个函数,并尝试将其作为函数调用传递给需要ref的函数时,编译时错误将立即在程序员的脸上显现,并带有明确的错误消息。所以我会说,这是更多的未来维护者友好...

+0

对未定义函数的调用可以像使用声明的静态全局一样进行编译。这两个都会导致链接器错误。 – rubenvb