Подтвердить что ты не робот

Не вызывает ли std:: кусочный_construct нарушение ODR?

'std:: piecewise_construct', определенный в <utility> , имеет внутреннюю связь, поскольку он объявлен 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)
    };
}

// translation unit 1
#include "a.hpp"

// translation unit 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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

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

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

Я полагаю, что одна и та же логика могла бы выполняться для кусочной_конструкции (но я не так много смотрел).