使用sfinae

时间:2015-09-11 20:59:37

标签: c++ templates overloading sfinae

我尝试使用SFINAE创建一个带模板重载方法的模板类,以排除未使用的方法,但在阅读了很多帖子和工时后,我无法弄清楚哪个是我的错误。

我的想法是创建一个包含4个参数的类模板,其中3个是可选项,2个选项参数将在重载方法中使用,只有正确的版本将被编译,类似这样(抱歉,我尝试使用)语法高亮,但我不知道如何)

template<char const q[], typename P1 = void, typename P2 = void, typename P3 = void>
class query
{
    char const * const value;
  public:
    query() : value(q) {};
    template<typename returnType, something else>
    returnType execute(P1 data1, P2 data2) { ..... };
    template<typename returnType, something else>
    returnType execute(P2 data2) { ..... };
    template<typename returnType, something else>
    returnType execute(P1 data1) { ..... };
    template<typename returnType, something else>
    returnType execute() { ..... };
}
constexpr char const q_str[] = "hola mundo";

class A {};
int main()
{
    query<q_str> v1;
    query<q_str, A> v2;

    A param;

    bool rc = v2.execute<bool>(param); << I expect to use the method execute(P1 data1)
    return 0;
}

所以,我的代码就是这个

template<char const q[], typename Tin = void, typename Tout = void, typename Twhere = void>
class query
{
    char const * const value;
public:
    typedef Tin ty_bind_in;
    typedef Tout ty_bind_out;

    query() : value(q) {};

    template<typename returnType,
             typename in = Tin,
             typename cond = typename std::enable_if< std::is_class<in>::value, void >::type>
    returnType execute(Tin &p_data)
    {
        returnType rs;
        return rs;
    };

    template<typename returnType>
    returnType execute()
    {
        returnType rs;
        return rs;
    };
};

constexpr char const q_str[] = "hola mundo";

class A {};

int main()
{
    query<q_str, A> q1;
    query<q_str> q2;

    return 0;
}

我正在使用此版本的gcc

gcc (Debian 4.9.2-10) 4.9.2

我要编译的行是

g++ -std=c++11 -g stack.cpp

我得到了这个错误

stack.cpp: In instantiation of ‘class query<((const char*)(& q_str))>’:
stack.cpp:40:15:   required from here
stack.cpp:19:13: error: forming reference to void
  returnType execute(Tin &p_data)
             ^

正如您所看到的,我在声明变量后立即收到错误。可能我做错了什么,但我无法弄清楚问题出在哪里。

编辑14/09:嗨,在解释Barry后我解决了这个问题并继续我的想法,所以我尝试为方法执行添加两个重载,第一个是这个(想法:当模板参数Tin和Twhere将是!= void时,此方法将起作用)

template<typename returnType,
         typename in = Tin,
         typename cond2 = typename std::enable_if<std::is_class<in>::value >::type, 
         typename where = Twhere,
         typename cond = typename std::enable_if< std::is_class<where>::value >::type>
returnType execute(in &p_data, where &p_where)
{
    returnType rs;
    return rs;
};

第二个就是这个(想法:这个方法在模板参数Twhere将会起作用时会起作用!= void)

template<typename returnType,
         typename where = Twhere,
         typename cond = typename std::enable_if< std::is_class<where>::value >::type>
returnType execute(where &p_data)
{
    returnType rs;
    return rs;
};

我收到以下错误

stack.cpp:39:13: error: ‘template<const char* q, class Tin, class Tout, class Twhere> template<class returnType, class where, class cond> returnType query<q, Tin, Tout, Twhere>::execute(where&)’ cannot be overloaded
  returnType execute(where &p_data)
             ^
stack.cpp:19:13: error: with ‘template<const char* q, class Tin, class Tout, class Twhere> template<class returnType, class in, class cond> returnType query<q, Tin, Tout, Twhere>::execute(in&)’
  returnType execute(in &p_data)

在我看来,这是因为Tin和Twhere的重载版本看起来等于参数但我不知道如何更正代码。

一些想法?。

提前谢谢你 最诚挚的问候

1 个答案:

答案 0 :(得分:3)

编写此功能时:

template <....>
returnType execute(Tin &p_data)

如果Tinvoid,那就是格式错误。虽然由于SFINAE将始终排除该条件,但函数本身仍然是格式错误的,并且允许编译器在那里出错。相反,您应该在那里使用模板参数:

template<typename returnType,
         typename in = Tin,
         typename cond = typename std::enable_if< std::is_class<in>::value, void >::type>
returnType execute(in& p_data)
                   ^^^^

请注意,void中的额外enable_if是不必要的,因为这是默认设置。如果你有一个C ++ 14编译器,你应该更喜欢std::enable_if_t,如果你没有,你应该在某个地方写这个别名只是为了实用性。那会让你写:

template<typename returnType,
         typename in = Tin,
         typename = enable_if_t<std::is_class<in>::value>>
returnType execute(in& p_data)

方式更少的字符,更容易理解重要的部分。