std::piecewise_construct
是在头文件<utility>中定义的,并且由于声明为constexpr
,因此具有内部链接。我想知道在头文件中使用std::piecewise_construct
是否会违反ODR(One Definition Rule)。例如:
a.hpp
#include <utility>
#include <tuple>
struct point
{
point(int x, int y)
: x(x), y(y)
{}
int x, y;
};
inline std::pair<point, point> f(int x1, int y1, int x2, int y2)
{
return {
std::piecewise_construct,
std::forward_as_tuple(x1, y1), std::forward_as_tuple(x2, y2)
};
}
翻译单元 1
#include "a.hpp"
翻译单元2
#include "a.hpp"
在TU 1中的f
中的std::piecewise_construct
与TU 2中的f
指的是不同的对象。我怀疑f
违反了ODR。N3290(可能也适用于ISO/IEC 14882:2011)在3.2/5中列出了以下ODR的例外情况:
“如果一个名字在D的所有定义中都指向具有内部或无链接的常量对象,并且对象具有相同的文字类型,并且使用常量表达式(5.19)初始化该对象,并且使用该对象的值(但不是地址),并且在D的所有定义中,该对象具有相同的值,则这个名字可以引用这个常量对象。”
f
几乎满足所有要求,但是“使用该对象的值(但不是地址)”对我来说似乎有歧义。虽然std::piecewise_construct_t
没有状态,但调用std::pair
的piecewise构造函数会涉及隐式声明的std::piecewise_construct_t
的复制构造函数的调用,其参数为const std::piecewise_construct_t&
。地址被“使用”了,不是吗?我很困惑。
参考文献:http://lists.boost.org/Archives/boost/2007/06/123353.php
std::cout
并没有被定义多次。它只是在各自的头文件中声明了。 - Johannes Schaub - litbstd::cout
是extern
并且只定义一次。 - wilhelmtellpiecewise_construct_t
的复制构造函数是平凡的,因此是constexpr
(7.1.5/4)。 - MSalters