std :: is_constructible непосредственный контекст и объявления друзей - PullRequest
1 голос
/ 08 марта 2019

Недавно я попытался обнаружить существование определенных частных конструкторов и столкнулся с проблемой, что std::is_constructible проверяет только непосредственный контекст и, следовательно, не распознает ничего таких конструкторов. После некоторого исследования я увидел, что в одном ответе здесь упоминается, что правильным способом является подружка рассматриваемого класса с std::is_constructible, чтобы он имел доступ.

Чтобы проверить, работает ли этот метод, я попытался выполнить следующий тестовый код

#include <type_traits>

class A {
private:
  template<typename, typename ...>
  friend struct std::is_constructible;

  A() = default;
};

int main() {
  static_assert(std::is_constructible<A>::value);
  static_assert(std::is_constructible_v<A>);
}

Интересно, что этот метод действительно работал с std::is_constructible в Visual Studio 2017, хотя я тогда начал сталкиваться с проблемами с std::is_constructible_v. В их реализации, вместо того, чтобы использовать шаблон псевдонима для самой структуры std::is_constructible, они вместо этого напрямую вызывают внутреннее свойство, используемое внутренне, что в свою очередь игнорирует объявление друга.

Думая, что это было ошибкой в ​​их стандартной реализации библиотеки, я затем протестировал в других компиляторах и обнаружил, что ни clang, ни gcc ни в коем случае не могли пропустить это утверждение, что заставило меня задуматься, может ли оно вообще работать как это вообще (некоторые комментарии в связанном посте, кажется, предполагают, что это ошибка, в то время как другие говорят, что это не должно принимать во внимание объявления друзей).

Таким образом, главный вопрос заключается в том, должен ли этот код работать правильно (как он должен иметь возможность доступа к приватному конструктору и передавать утверждения) так, как стандарт определяет доступ, ограниченный непосредственным контекстом? Подобный вопрос был также поставлен здесь , главное, в чем я не уверен, это точное определение, подразумеваемое «непосредственным контекстом» в этом случае, поскольку это немного отличается от примера в связанном вопросе.

Соответствующий отрывок из N4713 23.15.4.3.8 [meta.unary.prop] / 8:

Проверка доступа выполняется, как будто в контексте, не связанном с T и любым Args. Только действительность непосредственного контекста инициализация переменной считается.

Ответы [ 2 ]

5 голосов
/ 08 марта 2019

После некоторого исследования я увидел, что в одном из ответов упоминается, что правильным способом является подружка рассматриваемого класса с помощью std::is_constructible, чтобы он имел доступ.

Нет.Точно нет.Это совсем не правильный путь.Нет никакой гарантии, что это сработает.

Более того, нет никакой гарантии, что friend ing что-либо в стандартной библиотеке сделает то, что вы хотите.Стандартная библиотека не ваш друг . P1339 был одобрен в Kona и обновит SD-8 , чтобы дать стандартной библиотеке право предполагать, что пользователи этого не делают ... и библиотеке будет все равно, если изменения прервутсядружба пользователя вот так.

std::is_constructible_v<A> есть и должно быть false.

1 голос
/ 08 марта 2019

«Непосредственный контекст инициализации переменной» конкретно говорит о is_constructible_v, который является шаблоном переменной, который инициализируется значением is_constructible с теми же аргументами. То есть инициализация происходит за пределами вашего кода, поэтому контекст в вашем коде, где он выбирает значение указанной переменной, не имеет отношения к для доступности конструкторов. Полученное значение будет одинаковым независимо от того, откуда оно получено.

В сочетании с первым предложением стандарт фактически гласит: «это только общедоступный материал».

...