我尝试使用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的重载版本看起来等于参数但我不知道如何更正代码。
一些想法?。
提前谢谢你 最诚挚的问候
答案 0 :(得分:3)
编写此功能时:
template <....>
returnType execute(Tin &p_data)
如果Tin
是void
,那就是格式错误。虽然由于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)
方式更少的字符,更容易理解重要的部分。