方法编译时断言;仍然不工作 [英] method compile time assertion; still not working

查看:130
本文介绍了方法编译时断言;仍然不工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一种简单的方法来在模板中声明模板参数实现了一个方法(或其一个父类)。我已经阅读概念检查库,但很难找到一个简单的例子来做这样的简单检查。

I need a easy way to assert inside a template that a template parameter implements a method (or one of its parent classes). I've read Concept check library but is hard to find an easy example to do simple checks like this one.

我试图关注其他职位href =http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions>这一个和这另一个),我修改,所以我可以使它通用的许多方法类型(在我的例子中Foo(methodName)和has_foo(Checker名称)将正常工作,包装为宏参数,所以它可以用于任何方法)

I've tried to follow other posts (like this one and this other one), which i've modified so i can make it generic for many method types (in my example Foo (methodName) and has_foo (Checker name) will, once working correctly, be wrapped as macro arguments so it can be used for any method)

现在的代码是这样的:

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 with -std = c ++ 0x option所以static_assert被识别)我得到这个:

When i compile this example code (g++ 4.4.3 ubuntu with -std=c++0x option so the static_assert is recognized) i get this:

$ 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)"

正在等待,(注意Connector< Bla1> a已注释)我的第一个问题是:

wait just right there, (notice that Connector< Bla1 > a is commented) my first question is:

1)我是否正确地假设如果断言被评估,包含的模板正在被实例化?

1) am i right to assume that if the assertion is being evaluated, the containing template is being instantiated?

编辑:由GMan回答:在解析期间评估static_assert,而不是在实例化模板时。使用sizeof(TypeToBeChecked)== 0替换false会使它绑定到编译时

answered by GMan: the static_assert is evaluated during parsing, and not when the template is instantiated. Replacing false with sizeof(TypeToBeChecked)==0 makes it bound to compile-time

2)我是正确的假设,因为连接器模板类中的静态断言是实例化has_foo与int(int,double)签名,那么单参数和无参数的特殊化不应该被实例化?我的假设有什么问题?

2) am i right to assume that since the static assert inside Connector template class is instantiating has_foo with int(int, double) signature, then the single-parameter and parameterless specializations should NOT be instantiated? whats wrong with my assumptions?

编辑:这个假设是正确的,但现在我固定根据1)答案,实例化过程现在表现为预期

this assumption is right but now that i fixed according to 1) answer, the instantiation process is now behaving as expected

3)如果我取消注释Connector& Bla1>一个行,我会期望它失败(因为Bla1只有一个带有单个参数签名的Foo,但它不是。任何想法可能是错误的,特别考虑到第一个链接

3) if i uncomment the Connector< Bla1 > a line, i would expect it to fail (since Bla1 only has a Foo with a single parameter signature. However it is not. Any idea what might be wrong? specially taking in consideration the first linked post

推荐答案

考虑第一个链接问题中的答案的评论(这一个),你的模板检查是否有一个成员 Foo ,但不检查该成员的签名。

Taking into account also the comments on the answer in the first linked question (this one), your template checks if there is a member Foo, but it does not check the signature of that member.

要检查签名,您需要这样的代码(检查 operator()可以使用指定的参数调用;从 this usenet post on comp.lang.c ++。moderated by Roman.Perepelitsa@gmail.com):

To check the signature, you need code like this (checks for operator() that can be invoked with specified arguments; reproduced from this usenet post on comp.lang.c++.moderated by 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));

}

这篇关于方法编译时断言;仍然不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆