我有一个名为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();
};
我该如何正确地做到这一点?感谢。
答案 0 :(得分:2)
从你的问题的标题我假设你真的不需要一个派生自true_type或false_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()不接受任何参数的情况。只有当f返回void时才需要std :: add_pointer,因为sizeof(void)是非法的。
答案 1 :(得分:1)
我昨天为拉丁语写了一张拉普拉兹 “可能重复 Check if a class has a member function of a given signature” 并没有改变主意。
我认为这个问题可以解决这个问题
“A)如何检查某个类是否具有给定签名的成员函数
B)如何坚持课堂模板论证是一门课程
根据A)“。到B)在这种情况下,我会回答static_assert
,因为
提问者显然对enable_if
替代品不感兴趣。
这是一个适应my answer to
"traits for testing whether func(args) is well-formed and has required return type"的解决方案
该解决方案假定has_f<T>::value
当前且仅为真
如果公共成员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;
}
(使用clang 3.2,gcc 4.7.2 / 4.8.1构建)
答案 2 :(得分:0)
这在回答您的问题和提供问题的解决方案之间有一个很好的界限,但没有直接回答您的问题,但我认为您可能会觉得这很有帮助。
有关背景信息,请查看this question。作者提到他不喜欢Boost的解决方案,我也不特别喜欢那里提出的解决方案。我正在写一个快速的&amp;脏序列化库(想想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);
}
};
如果您可以将您的需求归结为一套简单的规则,并且可以使用稍微不那么通用的解决方案,我认为这种方法效果很好。