C++ 如何创建一个仅在其类型具有特定成员函数时才编译的类?
我有一个名为C++ 如何创建一个仅在其类型具有特定成员函数时才编译的类?,c++,c++11,C++,C++11,我有一个名为has\u 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
has\u 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 {};
如何正确地执行此操作?谢谢。根据您问题的标题,我假定您并不真正需要从true\u type或false\u 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 );
};
模板
结构编译\u如果\u有\u f
{
静态常数size\u t dummy=sizeof(
std::add_指针f())>:type);
};
这适用于f()不应接受任何参数的情况。std::add_指针仅在f返回void时才需要,因为sizeof(void)是非法的。这在回答您的问题和提供问题的解决方案(但不直接回答您的问题)之间划出了一条细线,但我想您可能会觉得这很有帮助 有关背景信息,请查看。作者提到他不喜欢Boost的解决方案,我也不特别喜欢那里提出的方案。我正在编写一个快速而肮脏的序列化库(想想python的封送),在这里您可以调用对象上的
serialize(object,ostream)
来序列化它。我意识到我想要对四件事中的一件进行函数调用:
对象
是普通的旧数据,只需写出大小和原始数据即可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);
}
};
#包括
#包括
#包括
#包括
//POD对象的模板专门化
模板
typename std::enable_if::type
串行(常数T&out,标准::ostream&os)
{
操作系统写入((const char*)&out,sizeof(T));
返回os.good();
}
//非POD对象必须具有成员函数“serialize(std::ostream)”
模板
typename标准::如果<,则启用!std::is_pod::value,bool>::type
串行(常数T&out,标准::ostream&os)
{
返回。串行(os);
}
//此处对常见容器对象进行了其他专门化
模板
bool串行(常量std::vector&out,std::ostream&os)
{
const size_t vec_size=out.size();
如果(!串行(向量大小,操作系统))
返回false;
对于(size_t i=0;i
如果你能将你的需求归结为一套简单的规则,并能接受一个稍微不那么通用的解决方案,我认为这种方法很有效。I+1ed rapptz forday for
“可能的副本 " 我也没有改变主意 我想这个问题对我来说是有争议的 “A)如何检查类是否具有给定签名的成员函数,以及 B) 如何坚持类模板参数是类 根据A)“。对于B)在这种情况下,我将用
静态断言回答,因为
提问者显然对enable\u if
备选方案不感兴趣
这里有一个适合的解决方案
此解决方案假定has_f::value
应为true,当且仅当
如果确实存在公共成员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;
}
#包括
模板
结构有
{
模板
静态constexpr布尔测试(
decltype(std::declval().f())*prt){
返回std::is_same::value;
}
模板
静态constexpr布尔测试(…){
返回false;
}
静态常量布尔值=测试(静态_转换(nullptr));
};
//测试。。。
结构i__f
{
无效f();
};
结构我没有
{
无效f(int);
};
结构i\u也\u没有
{
int f();
};
结构我不太有
{
int f()常数;
};
结构我当然没有
{};
结构i\u已重载\u f
{
无效f();
无效f(int);
};
结构i_已继承:i_已
{};
#包括
模板
结构必须具有{
静态断言(有f::值,“T没有f”);
};
int main()
{
必须具有t0;(无效)t0;
必须有(无效)t1;
必须有t2;(无效)t2;
必须\u有\u f t3;(void)t3;//静态\u断言失败
必须\u有\u f t4;(void)t4;//静态\u断言失败
必须\u有\u f t5;(void)t5;//静态\u断言失败
必须\u有\u f t6;(void)t6;//静态\u断言失败
必须\u有\u f t7;(void)t7;//静态\u断言失败
返回0;
}
(使用clang 3.2、gcc 4.7.2/4.8.1构建)如果f
过载怎么办?中的开始/结束特征检查有一些检查成员的示例。是否要检测模板?重载函数?继承的函数?@johanneschaub litb No,f
不带参数,是类中的常规void
函数。1)可能的重复项需要typename std::add_pointer…
进行编译。2) 我发现GCC4.7.2/4.8.1(与Clang3.2不同)不会在dummy
上呕吐,除非对其进行评估。需要静态断言
。3) 也允许f
@MikeKinghan的任何返回类型,感谢您的更正。我在VisualStudio2010中测试了这段代码,这就是为什么我忘记了typename
(VS在某些情况下不需要它)
#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;
}