C ++ especialização de modelo sem a função padrão
-
06-07-2019 - |
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
Por exemplo, GetGlobal
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!
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);