std :: is_constructible retorna um valor inconsistente para o construtor privado

13

Quais são as regras pelas quais std::is_constructiblelida com construtores privados? Dado o seguinte código:

#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();
}

Isso imprime 0( ideona ), ou seja, Tnão é construtível por padrão.

Descomentando a linha comentada, ela imprime 11( ideona ) e, de Trepente, tornou-se padrão construtível.

Eu pude encontrar um raciocínio para apoiar os dois resultados, mas não entendo como a inclusão da linha comentada altera o resultado do segundo. Isso está de alguma forma invocando o UB? Isso é um bug do compilador? Ou é std::is_constructiblerealmente tão inconsistente?

zennehoy
fonte
11
Parece um bug do GCC, clang 9 impressões00
Yksisarvinen 02/03
11
Outro pensamento estranho que noto ao compilar na minha máquina com c ++ 17 g ++ 9.2.1 / g ++ - 10.0 e substituir std :: is_constructible <...> :: value por is_constructible_v <...>, é que o resultado muda para 00
mutableVoid
11
@mutableVoid De fato - e parece que a ::valueversão é capaz de alterar a saída daqueles que vieram antes: godbolt.org/z/zCy5xU Descomente a linha comentada e tudo se torna 1: s no gcc.
Ted Lyngmo
11
Outra maneira de consertá-lo: godbolt.org/z/EKaP3r, então basicamente esse é algum tipo de bug de ordem de avaliação.
Marek R
2
@mutableVoid Você nem precisa instanciar o modelo de função para que ele se torne verdadeiro. Neste exemplo, ele retorna, falsemas se o modelo da função não é comentado, ele retorna repentinamente true: godbolt.org/z/zqxdk2
Ted Lyngmo

Respostas:

3

std::is_constructibledeve retornar falsenesse cenário porque o construtor não está acessível.

Conforme apontado abaixo da pergunta, o comportamento descrito na pergunta é causado por um bug no GCC / libstdc ++. O bug é relatado aqui e, de acordo com o Bugzilla, relacionado a se não é causado por um bug de controle de acesso para classes em funções de modelo que não foram resolvidas por um bom tempo. O relacionamento entre os dois bugs é retirado do comentário do Jonathan sobre o Bugzilla do Bugzilla, que parece ter detectado a conexão entre os dois bugs primeiro.

Isso também está implícito no fato de que o comportamento desse cenário no GCC se torna correto ao excluir o construtor em vez de torná-lo privado:

class Class {
    Class() = delete;
};

que imprime 0e 00respectivamente. Esta é a saída correta (que clanginforma corretamente no cenário com um construtor privado também).

Isso poderia explicar a mudança de comportamento observada ao comentar na linha, porque dentro da função na estrutura de modelo , a verificação de acesso não funciona e relata que o construtor está acessível quando não está. Quando a característica é verificada novamente na próxima linha ou possivelmente em um local completamente diferente (como é o caso aqui ), ela já foi instanciada e, portanto, produz a resposta errada.

mutableVoid
fonte