如何创建一个只在其类型具有特定成员函数时才编译的类?
How do I make a class that only compiles when its type has a certain member function?
我有一个名为has_f
的类,我希望它只接受具有f
成员函数的模板参数。我该怎么做呢?这是我尝试过的:
template <typename T, typename = void>
struct has_f : std::false_type {};
template <typename T>
struct has_f<
T,
typename = typename std::enable_if<
typename T::f
>::type
> : std::true_type {};
但是我得到一些隐晦的错误。下面是我想使用的类:
struct A
{
void f();
};
我如何正确地做到这一点?谢谢。
从你的问题的标题,我假设你并不真的需要一个类型派生自true_type或谬误-只是为了防止编译如果方法f不存在。如果是这种情况,并且您还需要该方法的特定签名(至少在参数方面),那么在c++ 11中可以这样做:
template <typename T>
struct compile_if_has_f
{
static const size_t dummy = sizeof(
std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};
这适用于f()不应该接受任何参数的情况。Std::add_pointer只有在f返回void时才需要,因为sizeof(void)是非法的。
可能的复制品检查类是否具有给定签名的成员函数。我也没有改变主意。
我认为这个问题可以解压缩到A)如何检查类是否具有给定签名的成员函数和B)如何坚持一个类模板参数是一个类A)"。在这种情况下,我会用static_assert
来回答B),因为提问者显然对enable_if
选项不感兴趣。
这是一个使我的答案适应的解决方案"用于测试func(args)是否格式良好并具有所需返回类型的特征"这个解决方案假设has_f<T>::value
当且仅为真如果public成员void T::f()
存在,即使T
重载f
或继承f
。
#include <type_traits>
template<typename T>
struct has_f
{
template<typename A>
static constexpr bool test(
decltype(std::declval<A>().f()) *prt) {
return std::is_same<void *,decltype(prt)>::value;
}
template <typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<T>(static_cast<void *>(nullptr));
};
// Testing...
struct i_have_f
{
void f();
};
struct i_dont_have_f
{
void f(int);
};
struct i_also_dont_have_f
{
int f();
};
struct i_dont_quite_have_f
{
int f() const;
};
struct i_certainly_dont_have_f
{};
struct i_have_overloaded_f
{
void f();
void f(int);
};
struct i_have_inherited_f : i_have_f
{};
#include <iostream>
template<typename T>
struct must_have_f{
static_assert(has_f<T>::value,"T doesn't have f");
};
int main()
{
must_have_f<i_have_f> t0; (void)t0;
must_have_f<i_have_overloaded_f> t1; (void)t1;
must_have_f<i_have_inherited_f> t2; (void)t2;
must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
must_have_f<int> t7; (void)t7; // static_assert fails
return 0;
}
(由3.2叮当声,gcc 4.7.2/4.8.1)
在回答你的问题和为你的问题提供解决方案而不是直接回答你的问题之间有一条微妙的界限,但我认为这可能会对你有所帮助。
有关背景,请查看这个问题。作者提到他不喜欢Boost的解决方案,我也不是特别喜欢那里提出的解决方案。我正在写一篇简短的文章。脏序列化库(想想python的marshal),你可以在对象上调用serialize(object, ostream)
来序列化它。我意识到我希望这个函数调用到以下四个对象之一:
- 如果
object
是普通的旧数据,只需写出大小和原始数据 - 如果
object
是我用自己的成员函数(object::serialize
)创建的类,那么调用该成员函数 - 如果有模板专门化的类型,使用它。
- 如果以上都不为真,则抛出编译错误;序列化函数使用不正确。
当我写代码的时候,我尽量避免那些"棘手的"或者一眼就看不懂的东西。我认为这个解决方案可以解决同样的问题,而不需要使用必须思考几个小时才能理解的代码:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
如果你可以把你的需求归结为一组简单的规则,并且可以接受一个稍微不那么通用的解决方案,我认为这个方法很好。
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针