Function Overloading Based on Arbitrary Properties of Types doesn't work

。_饼干妹妹 提交于 2019-12-22 12:39:32

问题


In the example below, I need to extract some values. I have an efficient extractor, which can work with builtin types, and an inefficient template that can work with everything. To choose between these, I want to use Function Overloading Based on Arbitrary Properties of Types. Here is my code:

#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;
}    

When I build the compiler complains:

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

When comment out the extraction and have only the traits printed, I get correct results:

./main
native extractor for std::string: 0
native extractor for double:      1

On the error listing you can see that for double the compiler passes the prototype on line 32, goes to 37 and prints error. The question is, why the SFINAE principle is not applied here?


回答1:


SFINAE only works when certain errors (like the ones you have) happen in declaration part. In your case they happen in definition. You have to rewrite your code so that enable_if is used in declaration, in your case of struct extract_caller.




回答2:


The code I got by fixing the problem doublep mentioned:

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);
    }
};

This can be used as

extract_caller::extract(string_value);
extract_caller::extract(double_value);


来源:https://stackoverflow.com/questions/9556924/function-overloading-based-on-arbitrary-properties-of-types-doesnt-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!