2

テンプレート パラメーターがメソッド (またはその親クラスの 1 つ) を実装していることをテンプレート内でアサートする簡単な方法が必要です。私は概念チェックライブラリを読みましたが、このような単純なチェックを行う簡単な例を見つけるのは難しいです.

私は他の投稿(この投稿やこの投稿など)をフォローしようとしましたが、これを変更して、多くのメソッドタイプ(私の例ではFoo(メソッド名)と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)"

そこで待ってください (Connector< Bla1 > a がコメントされていることに注意してください) 私の最初の質問は次のとおりです。

1) アサーションが評価されている場合、含まれているテンプレートがインスタンス化されていると仮定するのは正しいですか?

編集: GMan による回答: static_assert は、テンプレートがインスタンス化されたときではなく、解析中に評価されます。false を sizeof(TypeToBeChecked)==0 に置き換えると、コンパイル時にバインドされます

2) コネクタ テンプレート クラス内の静的アサートが int(int, double) シグネチャを使用して has_foo をインスタンス化しているため、単一パラメーターおよびパラメーターなしの特殊化をインスタンス化するべきではないと仮定するのは正しいですか? 私の仮定の何が問題なのですか?

編集:この仮定は正しいですが、1)の答えに従って修正したので、インスタンス化プロセスは期待どおりに動作しています

3) Connector< Bla1 > 行のコメントを外すと、失敗すると予想されます (Bla1 には 1 つのパラメーター署名を持つ Foo しかないためです。ただし、そうではありません。何が問題なのか、特に最初の考慮事項を考慮してリンクされた投稿

4

1 に答える 1

2

最初のリンクされた質問 ( this one )の回答に関するコメントも考慮して、テンプレートは member が存在するかどうかをFoo確認しますが、そのメンバーの署名は確認しません。

署名を確認するには、次のようなコードが必要です (operator()指定された引数で呼び出すことができるかどうかを確認します。comp.lang.c++ に関するこのusenet の投稿から複製します。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));

}
于 2010-10-27T11:19:15.193 に答える