Разве std :: piecewise_construct не вызывает нарушения ODR? - PullRequest
24 голосов
/ 03 октября 2011

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"

std::piecewise_construct в f в TU 1 относится к объекту, отличному от объекта в f в TU 2. Я подозреваю, что f нарушает ODR.

N3290 (возможно, также ISO / IEC 14882: 2011) говорит, что следующий случай является исключением из ODR, в 3.2 / 5:

имя может ссылаться на const-объект с внутренней связью или без нее, если объект имеет одинаковый литеральный тип во всех определениях D, а объект инициализируется с помощью константного выражения (5.19) и значения (но не адрес) объекта, и объект имеет одинаковое значение во всех определениях 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 ]

6 голосов
/ 03 октября 2011

Похоже, что у вас уже есть свой ответ в этой рассылке.Да, по моему мнению, это неопределенное поведение или, по крайней мере, недостаточно четкое определенное поведение.

См. это обсуждение usenet для обсуждения того же вопроса.

0 голосов
/ 03 октября 2011

ИМХО, при ODR нет конфликта.

Безымянное пространство имен имеет тот же эффект, что и разметка объектов для внутренней связи (статическая). Это действительно означает, что каждый TU использует свои собственные уникальные определения для таких типов / функций.

То, как я на них смотрю, как работают заполнители (:::: _ 1 и конкурирующие разновидности), не столько экземпляром, сколько выводом типа времени компиляции:

_1, _2 и т. Д. Являются просто местозаполнителями, и они не обязательно должны быть совместимыми (значения не нужно передавать из одного TU в другой, они передаются как выводимые параметры типа только и, как таковой, предполагается, что их фактический тип будет иметь identity из текущего TU).

IOW: Вы можете легко определить свои собственные заполнители, специализируя некоторые черты, и они все равно должны работать как шарм.

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

Полагаю, та же логика могла бы быть применима и для кусочно-конструктивного исполнения (но я не слишком много на это смотрел).

...