std::p iecewise_construct不会导致ODR违规吗?

Doesn't std::piecewise_construct cause a ODR violation?

本文关键字:ODR iecewise construct std      更新时间:2023-10-16

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"

图1中f中的std::piecewise_construct所指的对象与图2中f所指的对象不同。我怀疑f违反了ODR。

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

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

f几乎满足了所有的要求,但是"使用对象的值(而不是地址)"对我来说似乎模棱两可。的确,std::piecewise_construct_t没有状态,但是对std::pair的分段构造函数的调用涉及到对std::piecewise_construct_t的隐式声明的复制构造函数的调用,其参数是const std::piecewise_construct_t &。地址是used,对吧?

我很困惑。

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

看来你已经在那个boost邮件列表帖子中得到了答案。是的,在我看来,这是一种未定义的行为,或者至少是定义不够明确的行为。

请参阅此用户组讨论以了解正在讨论的相同问题。

我认为ODR下没有冲突。

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

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

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

ow:你可以很容易地定义你自己的占位符通过专门的一些特征,他们应该仍然像一个魅力。

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

我想同样的逻辑可以适用于piecewise_construction(但我还没有看那么多)。