【发布时间】:2018-06-27 02:42:25
【问题描述】:
我看到很多库代码使用以下模式来支持 C++11/C++14/C++17。我有兴趣了解“ODR 违规”和链接器问题是否/为什么/在多大程度上是可以的。
我将参考 Howard Hinnant 的 Date 库中的一个 sn-p,它最近被提议用于标准化。
https://github.com/HowardHinnant/date/blob/master/include/date/date.h
首先,我们检查_MSC_VER 和__cplusplus 之类的内容,以尝试找出我们所针对的C++ 编译器和标准(在某些情况下只能粗略地完成),并将一些标记定义为@987654324 @关键字,或空白。
#if defined(_MSC_VER) && (!defined(__clang__) || (_MSC_VER < 1910))
// MSVC
# if _MSC_VER < 1910
// before VS2017
# define CONSTDATA const
# define CONSTCD11
# define CONSTCD14
# define NOEXCEPT _NOEXCEPT
# else
// VS2017 and later
# define CONSTDATA constexpr const
# define CONSTCD11 constexpr
# define CONSTCD14 constexpr
# define NOEXCEPT noexcept
# endif
#elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150
// Oracle Developer Studio 12.6 and earlier
# define CONSTDATA constexpr const
# define CONSTCD11 constexpr
# define CONSTCD14
# define NOEXCEPT noexcept
#elif __cplusplus >= 201402
// C++14
# define CONSTDATA constexpr const
# define CONSTCD11 constexpr
# define CONSTCD14 constexpr
# define NOEXCEPT noexcept
#else
// C++11
# define CONSTDATA constexpr const
# define CONSTCD11 constexpr
# define CONSTCD14
# define NOEXCEPT noexcept
#endif
然后,许多成员函数等都使用这些宏进行注释:
// date composition operators
CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT;
CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT;
CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT;
CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT;
CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT;
CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT;
CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT;
CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT;
CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT;
CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT;
CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT;
现在,假设我有一个程序,其中包含一些以 C++11 标准编译的库和一些以 C++14 标准编译的库,其中许多都包含此文件并使用这些函数。
这意味着,标记为CONSTCD14 的函数将在C++14 翻译单元中标记为constexpr,而在C++11 编译单元中将不会标记为constexpr。让我们假设这些函数在两种翻译单元中都使用了 ODR。
- 这是否违反 ODR?
- 这里的 ODR 是不是没有意义,因为标准文档只涉及单一语言标准,并没有指定标准之间的互操作性?
-
constexpr会影响函数的名称修改吗? - 我应该期望在链接最终程序时找到此类函数的 C++11 和 C++14 版本,还是期望如果它们是内联的,则链接器将选择 C++11 或C++14 版本,如果唯一的区别是 constexpr 注释,它们将是相同的吗?
- 我是否应该期望这样的程序(取决于不同语言标准的同一库,其中
constexpr注释可能因所使用的语言标准而异)“工作”,以及这种以不同语言标准编译相同头文件的安排作为轻微的技术债务,还是应该将这种情况视为错误?
【问题讨论】:
标签: c++ c++11 c++14 language-lawyer one-definition-rule