Pergunta

Eu tenho o seguinte código que compila e funciona bem:

template<typename T>
T GetGlobal(const char *name);

template<>
int GetGlobal<int>(const char *name);

template<>
double GetGlobal<double>(const char *name);

No entanto quero remover a função de "default". Ou seja, eu quero fazer todas as chamadas para GetGlobal onde 't' não é um int ou um duplo erro.

Por exemplo, GetGlobal () deve ser um erro de tempo de compilação.

Eu tentei simplesmente apagar a função padrão, mas, como eu imaginava, eu recebi um monte de erros .. Então, há uma maneira de "desativar"-lo e permitir chamadas apenas para as versões especializadas do função?

Obrigado!

Foi útil?

Solução

Para obter um erro de compilação implementá-lo como:

template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined

Se você usar o impulso que você poderia torná-lo mais elegante:

template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }

garantias C ++ padrão que não há tal tipo que tem sizeof igual a 0, então você vai ter um erro em tempo de compilação.

Como SBI sugeriu em seus comentários o último poderia ser reduzido para:

template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }

Eu prefiro a primeira solução, porque dá mensagem de erro mais clara (pelo menos no Visual C ++) do que os outros.

Outras dicas

Embora seja uma questão antiga e ultrapassada, pode notar que C++11 tinha resolvido esta questão usando funções excluídos:

template<typename T>
T GetGlobal(const char *name) = delete;

template<>
int GetGlobal<int>(const char *name);

Atualizar

Isso não irá compilar sob MacOS llvm 8. É devido a um defeito de 4 anos de idade ainda paira (ver este bug relatório ).

A seguinte solução vai caber a questão (usando uma construção static_assert).

template<typename T>
T GetGlobal(const char *name) {
    static_assert(sizeof(T) == 0, "Only specializations of GetGlobal can be used");
}

template<>
int GetGlobal<int>(const char *name);

Atualizar

O Visual Studio 15.9 tem a mesma bug. Use a solução alternativa anterior para ele.

Se você não implementá-lo, você vai pelo menos conseguir um erro de vinculador. Se você quiser um erro de compilação, você poderia fazer isso com modelos de classe:

template<typename T>
struct GlobalGetter;

template<>
struct GlobalGetter<int> {
  static int GetGlobal(const char *name);
};

template<>
struct GlobalGetter<double> {
  static double GetGlobal(const char *name);
};

template<typename T>
T GetGlobal(const char *name)
{
  return GlobalGetter<T>::GetGlobal(name);
}

Gostaria de sugerir não para realmente fornecer uma implementação, apenas uma declaração nua do método.

A outra opção seria a utilização de um assert em tempo de compilação. Impulso tem um número de tais animais.

namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
                            boost::same_type<T, int> >));

Há também o seu homólogo versão de mensagem, o que ajudaria.

A seguir, são técnicas alternativas ao uso de impulso:

Declare um typedef para um nome dependente

Isso funciona porque pesquisa de nome para NÃO só ocorre quando 'T' foi substituída. Esta é uma versão similar (mas legal) do exemplo dado por Kirill

template <typename T>
T GetGlobal (const char * name) {
    typedef typename T::DONT CALL_THIS_FUNCTION;
}

Use um tipo de retorno incompleto

Esta técnica não funciona para especializações, mas ele vai trabalhar para sobrecargas. A idéia é que seu legal para declarar uma função que retorna um tipo incompleto, mas não chamá-lo:

template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top