std :: is_constructible возвращает несовместимое значение для частного конструктора

13

Каковы правила, по которым std::is_constructibleобрабатываются частные конструкторы? Учитывая следующий код:

#include <iostream>

class Class {
private:
    Class() { }
};

template <typename T>
class Test {
public:
    static void test() {
        std::cout
            //<< std::is_constructible<Class>::value
            << std::is_constructible<T>::value
            << std::endl;
    }
};

int main() {
    Test<Class>::test();
}

Это печатает 0( ideone ), т. Е.T Не является конструируемым по умолчанию.

Раскомментируя закомментированную строку, она печатает 11( ideone ), поэтому Tнеожиданно стала конструируемой по умолчанию.

Я мог бы найти обоснование для поддержки обоих результатов, но я не понимаю, как включение закомментированной строки меняет результат второго. Это как-то вызывает UB? Это ошибка компилятора? Или это std::is_constructibleдействительно противоречиво?

zennehoy
источник
1
Похоже на ошибку GCC, лязг 9 отпечатков00
Yksisarvinen
1
Еще одна странная мысль, которую я замечаю при компиляции на моей машине с c ++ 17 g ++ 9.2.1 / g ++ - 10.0 и замене std :: is_constructible <...> :: value на is_constructible_v <...>, заключается в том, что результат изменяется на 00
mutableVoid
1
@mutableVoid Действительно - и кажется, что ::valueверсия способна изменить вывод тех, кто ей предшествует: godbolt.org/z/zCy5xU Раскомментируйте закомментированную строку, и все станет 1: s в gcc.
Тед Люнгмо
1
Еще один способ это исправить: godbolt.org/z/EKaP3r, так что в основном это какая-то ошибка порядка оценки.
Марек Р.
2
@mutableVoid Вам даже не нужно создавать экземпляр шаблона функции, чтобы он стал правдой. В этом примере он возвращается, falseно если шаблон функции не закомментирован, он неожиданно возвращает true: godbolt.org/z/zqxdk2
Тед Люнгмо,

Ответы:

3

std::is_constructibleдолжен вернуться falseв этом сценарии, потому что конструктор не доступен.

Как указано под вопросом, поведение, описанное в вопросе, вызвано ошибкой в ​​GCC / libstdc ++. Об этой ошибке сообщается здесь , и, согласно Bugzilla, она связана с, если не вызвана, ошибкой контроля доступа для классов в шаблонных функциях , которая не устранена в течение достаточно долгого времени. Взаимосвязь между двумя ошибками взята из комментария Джонатана Уэйкли к Bugzilla, который, похоже, первым обнаружил связь между двумя ошибками.

Это также подразумевается тем фактом, что поведение этого сценария в GCC становится правильным при удалении конструктора вместо того, чтобы сделать его закрытым:

class Class {
    Class() = delete;
};

который распечатывает 0и 00соответственно. Это правильный вывод (который clangправильно сообщает в сценарии с частным конструктором, а также).

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

mutableVoid
источник