Перегрузка функций, основанная на произвольных свойствах типов, не работает - PullRequest
1 голос
/ 04 марта 2012

В приведенном ниже примере мне нужно извлечь некоторые значения. У меня есть эффективный экстрактор, который может работать со встроенными типами, и неэффективный шаблон, который может работать со всем. Чтобы выбрать между ними, я хочу использовать Перегрузка функций на основе произвольных свойств типов . Вот мой код:

#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 здесь не применяется?

Ответы [ 2 ]

2 голосов
/ 04 марта 2012

SFINAE работает только тогда, когда определенные ошибки (например, те, которые у вас есть) происходят в декларации части. В вашем случае они бывают в определении . Вы должны переписать свой код так, чтобы enable_if использовался в объявлении, в вашем случае struct extract_caller.

0 голосов
/ 04 марта 2012

Код, который я получил, исправив упоминавшуюся проблему:

struct extract_caller
{
    template <typename T>
    static void extract(const T& val, typename enable_if<(bool)is_extractor_native<T>::val>::type * = 0)
    {
            extractor::extract(val);
    }

    template <typename T>
    static void extract(const T& val, typename enable_if<!(bool)is_extractor_native<T>::val>::type * = 0)
    {
            extract_generic(val);
    }
};

Это можно использовать как

extract_caller::extract(string_value);
extract_caller::extract(double_value);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...