В приведенном ниже примере мне нужно извлечь некоторые значения. У меня есть эффективный экстрактор, который может работать со встроенными типами, и неэффективный шаблон, который может работать со всем. Чтобы выбрать между ними, я хочу использовать Перегрузка функций на основе произвольных свойств типов . Вот мой код:
#include <string>
#include <iostream>
class extractor
{
public:
static void extract(const bool& val) { std::cout << "Specialized extractor called" << std::endl; }
static void extract(const double& val) { std::cout << "Specialized extractor called" << std::endl; }
};
template <typename T>
void extract_generic(const T& value) { std::cout << "Generic extractor called" << std::endl; }
template <typename T> struct is_extractor_native { static const bool val = false; };
template<> struct is_extractor_native<bool> {static const bool val = true; };
template<> struct is_extractor_native<double> {static const bool val = true; };
template <bool B, class T = void>
struct enable_if {
typedef T type;
};
template <class T>
struct enable_if<false, T> {};
template <typename T>
struct extract_caller
{
//line 32 below
static void extract(const T& val, typename enable_if<is_extractor_native<T>::val>::type * = 0)
{
extractor::extract(val);
}
//line 37 below
static void extract(const T& val, typename enable_if<!is_extractor_native<T>::val>::type * = 0)
{
extract_generic(val);
}
};
int main(void)
{
std::string string_value("hello");
double double_value(.123);
std::cout << "native extractor for std::string: " << (int)is_extractor_native<std::string>::val << std::endl;
std::cout << "native extractor for double: " << (int)is_extractor_native<double>::val << std::endl;
extract_caller<std::string>::extract(string_value);
extract_caller<double>::extract(double_value);
return 0;
}
Когда я собираю компилятор, жалуется:
g++ main.cpp -o main
main.cpp: In instantiation of ‘extract_caller<std::basic_string<char> >’:
main.cpp:50:29: instantiated from here
main.cpp:32:14: error: no type named ‘type’ in ‘struct enable_if<false, void>’
main.cpp: In instantiation of ‘extract_caller<double>’:
main.cpp:51:24: instantiated from here
main.cpp:37:14: error: no type named ‘type’ in ‘struct enable_if<false, void>’
make: *** [main] Error 1
При комментировании извлечения и печати только черт, я получаю правильные результаты:
./main
native extractor for std::string: 0
native extractor for double: 1
В списке ошибок вы можете видеть, что для double
компилятор передает прототип в строке 32, переходит к 37 и печатает ошибку. Вопрос в том, почему принцип SFINAE здесь не применяется?