【发布时间】:2013-07-29 15:54:08
【问题描述】:
我正在尝试编写一个模板类,它可能会或可能不会定义特定的成员函数,具体取决于其模板参数类型。此外,此成员函数的返回类型取决于模板参数成员(如果已定义)的返回类型。
以下是我的代码的最小示例
#include <iostream>
#include <type_traits>
template <typename T>
struct has_foo_int {
private:
template <typename U>
static decltype(std::declval<U>().foo(0), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) test_type;
enum { value = test_type::value };
};
template <typename T, bool HasFooInt>
struct foo_int_return_type;
template<typename T>
struct foo_int_return_type<T,false> {};
template<typename T>
struct foo_int_return_type<T,true> {
using type = decltype(std::declval<T>().foo(0));
};
template<typename T>
struct mystruct
{
T val;
//auto someMethod(int i) -> decltype(std::declval<T>().foo(0)) // error: request for member ‘foo’ in ‘std::declval<double>()’, which is of non-class type ‘double’
//auto someMethod(int i) -> typename foo_int_return_type<T,has_foo_int<T>::value>::type // error: no type named ‘type’ in ‘struct foo_int_return_type<double, false>’
template<typename R=typename foo_int_return_type<T,has_foo_int<T>::value>::type> R someMethod(int i) // error: no type named ‘type’ in ‘struct foo_int_return_type<double, false>’
{
return val.foo(i);
}
};
struct with_foo_int {
int foo(int i){
return i+1;
}
};
using namespace std;
int main(void)
{
mystruct<with_foo_int> ms1;
cout << ms1.someMethod(41) << endl;
mystruct<double> ms2;
return 0;
}
我希望代码编译良好并为ms1.someFunc(41) 输出 42。我还希望,如果有人不小心尝试在 ms2 上调用 someFunc,它将无法编译。
不幸的是,我尝试过的每个替代方案都失败了。第一个和第二个,我想我明白为什么它们不起作用了。
我读到here 说 SFINAE 仅适用于模板函数,因此我尝试提供一个虚拟模板参数来计算返回类型,但这也以同样的方式失败。
我显然不明白这里的某些东西,我错过了什么?是否有可能实现我想要做的事情?
谢谢。
附注我正在使用 g++ 4.7.3
P.p.s 我也尝试过 std::enable_if,但得到的结果与我的 foo_int_return_type 结构大致相同。
【问题讨论】:
-
函数本身需要将相关参数作为模板参数,否则在调用点没有替换,你不会得到SFINAE。一种流行的解决方法是使用虚拟参数,例如
template<class U = T, *insert SFINAE here with U instead of T*> -
有效!不过,我不确定为什么,如果您将此作为答案发布并解释,我会很乐意接受。
-
对于 SFINAE,编译器(或用户)需要推断(提供)一个类型,编译器稍后会尝试 S 替换和 F 一切
-
@Dan:不,触发 SFINAE 的表达式需要依赖 该函数的模板参数。
-
@Dan:
R是一个单一的类型,它要么是提供的,要么是推导的,但是在解决了那个类型之后就没有替代
标签: c++ templates c++11 sfinae decltype