утверждение времени компиляции метода; до сих пор не работает - PullRequest
2 голосов
/ 26 октября 2010

Мне нужен простой способ утверждать внутри шаблона, что параметр шаблона реализует метод ( или один из его родительских классов ).Я читал библиотеку концептуальных проверок, но трудно найти простой пример для выполнения простых проверок, подобных этой.

Я пытался следить за другими сообщениями (например, этой и этот другой ), который я изменил, чтобы я мог сделать его универсальным для многих типов методов (в моем примере Foo (methodName) и has_foo (имя Checker), после правильной работы, будут обернуты в качестве аргументов макроса, так чтоон может использоваться для любого метода)

код, который у меня есть на данный момент, такой:

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 a прокомментирован) мой первый вопрос:

1) Правильно ли я предположить, что если утверждение оценивается, то содержащий шаблон создается?

РЕДАКТИРОВАТЬ: ответил GMan: static_assert оценивается во время синтаксического анализа, а не при создании экземпляра шаблона.Замена false на sizeof (TypeToBeChecked) == 0 делает его связанным со временем компиляции

2) Правильно ли я предположить, что, поскольку статическое утверждение в классе шаблона Connector создает экземпляр has_foo с подписью int (int, double), тогда НЕ нужно создавать экземпляры специализаций с одним параметром и без параметров?что не так с моими предположениями?

РЕДАКТИРОВАТЬ: это предположение верно, но теперь, когда я исправил в соответствии с 1) ответом, процесс создания экземпляров теперь ведет себя как ожидалось

3), если я раскомментирую Соединитель строка, я бы ожидал, что она потерпит неудачу (поскольку Bla1 имеет только Foo с единственной сигнатурой параметра. Однако это не так. Любая идея, что может быть не так? Особенно с учетом первого связанного сообщения

1 Ответ

2 голосов
/ 27 октября 2010

Принимая во внимание также комментарии к ответу в первом связанном вопросе ( этот ), ваш шаблон проверяет, есть ли член Foo, но не проверяет подпись этого участника..

Чтобы проверить подпись, вам нужен такой код (проверяет operator(), который может быть вызван с указанными аргументами; воспроизводится из этого сообщения usenet на comp.lang.c ++.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));

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...