24

std::piecewise_construct,在 <utility> 中定义,自声明以来具有内部链接constexpr。我想知道std::piecewise_construct在标头中使用是否会违反 ODR。例如:

一个.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_constructinf指的是与fTU 2 中不同的对象。我怀疑f违反了 ODR。

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

如果对象在 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

4

2 回答 2

6

看来您已经在该提升邮件列表发布中找到了答案。是的,在我看来,这是未定义的行为,或者至少没有足够明确的定义行为。

有关正在讨论的同一问题,请参阅此 usenet 讨论

于 2011-10-03T11:55:32.750 回答
0

恕我直言,在 ODR 下没有冲突。

未命名的命名空间与为内部链接(静态)标记事物具有相同的效果。这确实意味着每个 TU 都对此类类型/功能使用自己独特的定义。

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

_1、_2 等只是占位符,它们并不真正需要兼容(值不需要从一个 TU 传递到另一个 TU,它们仅作为类型推断参数传递,因此推断它们的实际类型从identity当前的 TU 中获得)。

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

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

我想同样的逻辑也适用于piecewise_construction(但我没看过那么多)。

于 2011-10-03T12:03:42.500 回答