Parâmetros de modelo sem tipo

93

Eu entendo que o parâmetro de modelo sem tipo deve ser uma expressão integral constante. Alguém pode esclarecer o porquê disso?

template <std::string temp>
void foo()
{
     // ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.

Eu entendo o que é uma expressão integral constante. Quais são as razões para não permitir tipos não constantes std::stringcomo no trecho acima?

Mahesh
fonte
17
Um parâmetro de modelo é resolvido em tempo de compilação.
Etienne de Martel,

Respostas:

121

A razão pela qual você não pode fazer isso é porque expressões não constantes não podem ser analisadas e substituídas durante o tempo de compilação. Eles poderiam mudar durante o tempo de execução, o que exigiria a geração de um novo modelo durante o tempo de execução, o que não é possível porque os modelos são um conceito de tempo de compilação.

Aqui está o que o padrão permite para parâmetros de modelo sem tipo (14.1 [temp.param] p4):

Um parâmetro de modelo não-tipo deve ter um dos seguintes tipos (opcionalmente qualificado de cv):

  • tipo integral ou enumeração,
  • ponteiro para objeto ou ponteiro para função,
  • referência de lvalue para objeto ou referência de lvalue para função,
  • ponteiro para membro,
  • std::nullptr_t.
Xeo
fonte
6
@ALOToverflow: Isso se enquadra em "ponteiro para membro". Pode ser "ponteiro para função de membro" ou "ponteiro para dados de membro".
Xeo
4
É importante notar que para o caso de ponteiros para objetos (ou campos de instância), os objetos devem ter duração de armazenamento estático e ligação (externo pré C ++ 11, interno ou externo em C ++ 11), de modo que ponteiros para eles possam ser criado em tempo de compilação.
Theodore Murdock
2
Em C ++ 20, isso agora é permitido, desde que o tipo tenha uma igualdade estruturada forte, seja um literal, sem subobjetos mutáveis ​​/ voláteis e onde o operador da nave seja público.
Rakete1111
73

Isso não é permitido.

No entanto, isso é permitido:

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

Consulte §14.1 / 6,7,8 em C ++ Standard (2003).


Ilustração:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

Resultado:

can assign values locally
can assign values locally
can assign values locally...appended some string
Nawaz
fonte
7
@Mahesh: Porque o modelo basicamente define o endereço daquele std::stringponteiro ou objeto de referência. Se essa variável fosse local, você possivelmente obteria endereços diferentes toda vez que a função fosse chamada.
Xeo de
11
@Mahesh: Você não sabe como fica a pilha de chamadas em tempo de compilação. Antes de sua função, poderia ter sido chamado 10 outro ou 3 outros ou quantos outros, portanto, o endereço na pilha, no qual a string é criada pode mudar de chamada para chamada. Quando você tem um objeto com ligação externa, seu endereço é fixo durante a compilação / ligação.
Xeo,
2
@Xeo " seu endereço é corrigido durante a compilação / ligação. " Ou não, para código relocável ou independente de posição.
curioso
1
Esta resposta (atualmente) não parece responder à questão do OP, que era perguntar por que esse comportamento existe; esta resposta apenas reafirma o exemplo do OP sem oferecer qualquer explicação.
Quuxplusone de
1
Estou atrasado para a festa, parece que as dicas inteligentes também não funcionam
Nicholas Humphrey
28

Você precisa ser capaz de destruir os argumentos do modelo

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"bar">(); // different function!?

Agora, um implante precisaria criar uma sequência única de caracteres para um std::string ou, nesse caso, qualquer outra classe arbitrária definida pelo usuário, armazenando um valor particular, cujo significado não é conhecido pela implementação. Além disso, o valor de objetos de classe arbitrários não pode ser calculado em tempo de compilação.

É planejado permitir tipos de classe literais como tipos de parâmetro de modelo para pós-C ++ 0x, que são inicializados por expressões constantes. Esses poderiam ser mutilados por ter os membros de dados mutilados recursivamente de acordo com seus valores (para classes básicas, por exemplo, podemos aplicar profundidade primeiro, passagem da esquerda para a direita). Mas definitivamente não vai funcionar para classes arbitrárias.

Johannes Schaub - litb
fonte
10

Um argumento de modelo sem tipo fornecido em uma lista de argumentos de modelo é uma expressão cujo valor pode ser determinado em tempo de compilação. Esses argumentos devem ser:

expressões constantes, endereços de funções ou objetos com ligação externa ou endereços de membros de classe estáticos.

Além disso, literais de string são objetos com ligação interna, portanto, você não pode usá-los como argumentos de modelo. Você também não pode usar um ponteiro global. Literais de ponto flutuante não são permitidos, dada a possibilidade óbvia de erros de arredondamento.

Sadique
fonte
Você usou uma citação, então qual é a fonte? Eu gostaria de votar a favor, se houver uma fonte para a citação.
Gabriel Staples,