我需要一种简单的方法来在模板内断言模板参数实现一个方法(或其父类之一)。我已经阅读了概念检查库,但很难找到一个简单的例子来做这样的简单检查。
我已尝试关注其他帖子(例如this one和this other one),我已对其进行了修改,因此我可以将其设置为许多方法类型的通用(在我的示例中为Foo(methodName)和一旦正常工作,has_foo(检查器名称)将被包装为宏参数,因此它可以用于任何方法)
我目前的代码是这一个:
template <typename TypeToBeChecked, typename Sign>
class has_foo {
static_assert( false , "inside root declaration of " "has_foo" );
public:
static const bool result = false;
};
template <typename TypeToBeChecked , typename R>
class has_foo < TypeToBeChecked , R(void) >
{
static_assert( false , "inside specialization of " "has_foo" " for R(void)" );
class yes { char m;};
class no { yes m[2];};
struct BaseMixin { R Foo(){} };
struct Base : public TypeToBeChecked, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U> static no deduce(U*, Helper<R (BaseMixin::*)(), &U::Foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
template <typename TypeToBeChecked , typename R , typename ARG1>
class has_foo< TypeToBeChecked , R(ARG1) >
{
static_assert( false , "inside specialization of " "has_foo" " for R(ARG1)" );
class yes { char m;};
class no { yes m[2];};
struct BaseMixin { R Foo(ARG1){} };
struct Base : public TypeToBeChecked, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<R (BaseMixin::*)(ARG1), &U::Foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
template <typename TypeToBeChecked , typename R , typename ARG1 , typename ARG2>
class has_foo< TypeToBeChecked , R(ARG1, ARG2) >
{
static_assert( false , "inside specialization of " "has_foo" " for R(ARG1 , ARG2)" );
class yes { char m;};
class no { yes m[2];};
struct BaseMixin { R Foo(ARG1,ARG2){} };
struct Base : public TypeToBeChecked, public BaseMixin {};
template <typename T, T t>
class Helper{};
template <typename U>
static no deduce(U*, Helper<R (BaseMixin::*)(ARG1,ARG2), &U::Foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
template< typename Type >
struct Connector
{
static_assert( has_foo< Type , int(int, double) >::result , "Type has no Foo method" );
void Operate() {
Type t;
t.Foo(3);
}
};
struct Bla1 { int Foo(double f) { return (int)f; } };
struct Bla2 { int Foo(int g, double h) { return g+(int)h;} };
int main()
{
//Connector< Bla1 > a;
Connector< Bla2 > b;
};
当我编译这个示例代码(g ++ 4.4.3 ubuntu并使用-std = c ++ 0x选项以便识别static_assert)时,我得到了这个:
$ g++ test.cpp -std=c++0x -o test
test.cpp:72: error: static assertion failed: "inside root declaration of has_foo"
test.cpp:79: error: static assertion failed: "inside specialization of has_foo for R(void)"
test.cpp:93: error: static assertion failed: "inside specialization of has_foo for R(ARG1)"
test.cpp:108: error: static assertion failed: "inside specialization of has_foo for R(ARG1 , ARG2)"
等到那里,(注意连接器&lt; Bla1&gt; a被评论)我的第一个问题是:
1)我是否正确地假设如果正在评估断言,那么正在实例化包含的模板?
编辑:GMan回答:static_assert在解析期间进行评估,而不是在实例化模板时进行评估。用sizeof替换false(TypeToBeChecked)== 0使它绑定到编译时
2)我是否正确地假设由于Connector模板类中的静态断言是使用int(int,double)签名实例化has_foo,那么单参数和无参数的特化应该不被实例化?我的假设有什么不对?
编辑:这个假设是正确的,但现在根据1)答案修复,实例化过程现在表现得如预期的那样3)如果我取消注释连接器&lt; Bla1&gt;一行,我希望它失败(因为Bla1只有一个带有单个参数签名的Foo。但它不是。任何想法可能是什么错误?特别考虑到第一个链接的帖子
答案 0 :(得分:2)
考虑到第一个链接问题(this one)中对答案的评论,您的模板会检查是否有成员Foo
,但它不会检查该成员的签名。
要检查签名,您需要这样的代码(检查可以使用指定参数调用的operator()
;从comp.lang.c ++上的this usenet post复制。由Roman.Perepelitsa审核@ gmail.com):
template <typename Type>
class has_member
{
class yes { char m;};
class no { yes m[2];};
struct BaseMixin
{
void operator()(){}
};
struct Base : public Type, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<void (BaseMixin::*)(), &U::operator()>*
= 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)
(0)));
};
namespace details
{
template <typename type>
class void_exp_result
{};
template <typename type, typename U>
U const& operator,(U const&, void_exp_result<type>);
template <typename type, typename U>
U& operator,(U&, void_exp_result<type>);
template <typename src_type, typename dest_type>
struct clone_constness
{
typedef dest_type type;
};
template <typename src_type, typename dest_type>
struct clone_constness<const src_type, dest_type>
{
typedef const dest_type type;
};
}
template <typename type, typename call_details>
struct is_call_possible
{
private:
class yes {};
class no { yes m[2]; };
struct derived : public type
{
using type::operator();
no operator()(...) const;
};
typedef typename details::clone_constness<type, derived>::type
derived_type;
template <typename T, typename due_type>
struct return_value_check
{
static yes deduce(due_type);
static no deduce(...);
static no deduce(no);
static no deduce(details::void_exp_result<type>);
};
template <typename T>
struct return_value_check<T, void>
{
static yes deduce(...);
static no deduce(no);
};
template <bool has, typename F>
struct impl
{
static const bool value = false;
};
template <typename arg1, typename r>
struct impl<true, r(arg1)>
{
static const bool value =
sizeof(
return_value_check<type, r>::deduce(
(((derived_type*)0)->operator()(*(arg1*)0),
details::void_exp_result<type>())
)
) == sizeof(yes);
};
// specializations of impl for 2 args, 3 args,..
public:
static const bool value = impl<has_member<type>::result,
call_details>::value;
};
用法示例:
struct Foo
{
void operator()(double) const {}
void operator()(std::string) const {}
};
int main()
{
STATIC_ASSERT((is_call_possible<Foo, void(double)>::value));
STATIC_ASSERT((is_call_possible<Foo, void(int)>::value));
STATIC_ASSERT((is_call_possible<Foo, void(const char *)>::value));
STATIC_ASSERT((!is_call_possible<Foo, void(void *)>::value));
}