std :: piecewise_construct不会导致ODR违规吗?

时间:2011-10-03 11:35:18

标签: c++ c++11 constexpr linkage one-definition-rule

< utility>中定义的

std::piecewise_construct具有内部链接,因为它已声明为constexpr。我想知道在标头中使用std::piecewise_construct是否会违反ODR。例如:

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中std::piecewise_construct中的f指的是与TU 2中f不同的对象。我怀疑f违反了ODR。

N3290(也可能是ISO / IEC 14882:2011)表示以下案例是ODR的例外,在3.2 / 5中:

  

如果对象在D的所有定义中具有相同的文字类型,并且该对象使用常量表达式(5.19)初始化,并且值(但不是,则),则可以引用具有内部链接或无链接的const对象使用对象的地址),并且对象在D的所有定义中具有相同的值;

f几乎满足了所有要求,但“使用对象的值(但不是地址)”对我来说似乎很模糊。确实std::piecewise_construct_t没有状态,但调用std::pair的分段构造函数涉及调用std::piecewise_construct_t的隐式声明的复制构造函数,其参数为const std::piecewise_construct_t & 。地址是“使用过的”,不是吗?

我很困惑。

参考:http://lists.boost.org/Archives/boost/2007/06/123353.php

2 个答案:

答案 0 :(得分:6)

您似乎已经在该邮件列表发布中获得了答案。是的,在我看来,它是未定义的行为或至少没有足够清晰的定义行为。

有关正在讨论的同一事项,请参阅this usenet discussion

答案 1 :(得分:0)

恕我直言,ODR没有冲突。

未命名的命名空间与为内部链接(静态)标记内容具有相同的效果。 这确实意味着每个TU都使用他自己对这些类型/函数的唯一定义。

我看待它们的方式,占位符(:::: 1和竞争风格)如何工作,不是通过实例化,而是通过编译时类型推断:

_1,_2等只是占位符,它们实际上并不需要兼容(值不需要从一个TU传递到另一个,它们作为类型推断参数传递只是因为他们的实际类型被推断为具有来自当前TU的 identity

IOW:你可以通过专门化一些特性来轻松定义自己的占位符,它们应该仍像魅力一样。

namespace boost
{
    template<int I> struct is_placeholder< 
           my_funny_own_placeholder_no_ODR_involved<I> >
    {
        enum _vt { value = I };
    };
}

我认为相同的逻辑可以适用于piecewise_construction(但我没有看那么多)。