статичен ли в простом с ++? - PullRequest
12 голосов
/ 30 марта 2012

Проблема вкратце: Как можно реализовать функциональность static if, предложенную в c ++ 11, на простом языке c ++?

История и исходная проблема: Недавно у меня возникла такая проблема.Мне нужен класс Sender с интерфейсом, подобным

class Sender
{
   void sendMessage( ... );
   void sendRequest( ... );
   void sendFile( ... );
   // lots of different send methods, not important actually
}

. В некоторых случаях мне нужно будет создать DoubleSender , то есть экземпляр этого класса, который будет вызывать его методы дваждыто есть при вызове, скажем, метода sendMessage(...) одно и то же сообщение должно быть отправлено дважды.

Мои решения: Первый подход: Имейте члена isDouble, и в конце каждого вызова метода сделайте проверку

sendMessage(...) { ... if( isDouble ) { sendMessage( ... ); }

Ну, я не хочу этого, потому что на самом деле мне понадобится двойная публикация совсем недавно, и эта часть кода в критичном ко времени разделе будет на 98% пассивной.

Второй подход:
Наследовать класс DoubleSender от Sender и реализовывать его методы, такие как:

void DoubleSender::sendMessage( ... )
{
   Sender::sendMessage(...);
   Sender::sendMessage(...);
}

Ну, это приемлемо, но занимает много места неприятногокод (действительно много, потому что есть много различных send.. методов.

Третий подход: Представьте, что я использую C ++ 11 :).Затем я могу сделать этот класс универсальным и создать необходимую часть кода в соответствии с аргументом tempalte, используя static if:

enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
   void sendMessage(...)
   {
      // do stuff
      static if ( T == Single )
      {
         sendMessage(...);
      }
   }
};

Это короче, проще для чтения, чем в предыдущих решениях, не генерирует дополнительный код и.... это c ++ 11, который я, к сожалению, не могу использовать в своей работе.

Итак, вот где я пришел к своему вопросу - как я могу реализовать static if аналог в c ++?Кроме того, я был бы признателен за любые другие предложения о том, как решить мою первоначальную проблему.Заранее спасибо.

Ответы [ 4 ]

9 голосов
/ 30 марта 2012

Цитирование @ JohannesSchaubLitb

с моим static_if, работающим на gcc, можно это сделать:)
ограниченным образом

(см. Также здесь )

Этот трюк включает в себя специальную интерпретацию GCC спецификаций Lambdas в C ++ 11. Как таковой, он (вероятно) станет отчетом о дефектах по сравнению со стандартом. Это приведет к тому, что трюк больше не работает в более поздней версии GCC (он уже не работает в 4.7).

См. Ветку комментариев ниже для получения дополнительной информации от Johanness

http://ideone.com/KytVv:

#include <iostream>

namespace detail {
template<bool C>
struct call_if { template<typename F> void operator<<(F) { } };

template<>
struct call_if<true> {
  template<typename F>
  void operator<<(F f) { f(); }
};
}

#define static_if(cond) detail::call_if<cond>() << [&]

template<bool C, typename T>
void f(T t) {
  static_if(C) {
    t.foo();
  };
}

int main() {
  f<false>(42);
}
7 голосов
/ 30 марта 2012

Почему бы не сделать реализацию send политикой класса отправителя и использовать CRTP:

template<class Derived>
class SingleSenderPolicy
{
    public:
    template< class memFunc >
    void callWrapperImpl(memFunc f, ...)
    {
        static_cast<Derived *>(this)->f(...);
    }
};

template< class Derived >
class DoubleSenderPolicy
{
    public:
    template< class memFunc >
    void callWrapperImpl(memFunc f, ...)
    {
        static_cast<Derived *>(this)->f(...);
        static_cast<Derived *>(this)->f(...);
     }
};

template< class SendPolicy>
class Sender : public SendPolicy< Sender >
{
public:
    void sendMessage( ... )
    {
       // call the policy to do the sending, passing in a member function that
       // acutally performs the action
       callWrapperImpl( &Sender::sendMessageImpl, ... );
    }

    void doSomethingElse( ... )
    {
       callWrapperImpl( &Sender::doSomethingElseImpl, ... );
    }


protected:
    void sendMessageImpl(... )
    {
        // Do the sending here
    } 

    void doSomethingElseImpl(... )
    {
        // Do the sending here
    } 
};

Публичные функции sendXXX в вашем классе просто перенаправляют в оболочку вызова, передавая функцию-член, котораяреализует реальную функциональностьЭта функция-член будет вызываться в соответствии с SendPolicy класса.CRTP экономит использование связывания, чтобы обернуть аргументы и этот указатель с помощью функции-члена для вызова.

С одной функцией это на самом деле не сокращает объем кода, но если у вас многозвонки это может помочь.

Примечание. Этот код является каркасом, обеспечивающим возможное решение, он не был скомпилирован.

Примечание: Sender<DoubleSenderPolicy> и Sender<SingleSenderPolicy> - это совершенно разные типы и не имеют динамическогонаследственные отношения.

5 голосов
/ 04 апреля 2012

Большинство компиляторов делают постоянное свертывание и удаление мертвого кода, поэтому, если вы пишете регулярное выражение if, как это:

enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
   void sendMessage(...)
   {
      // do stuff
      if ( T == Single )
      {
         sendMessage(...);
      }
   }
};

Ветвь if будет удалена при генерации кода.

Необходимость static if - это когда операторы вызывают ошибку компилятора. Скажем так, у вас было что-то вроде этого (немного псевдо-код):

static if (it == random_access_iterator)
{
    it += n;
}

Поскольку вы не можете вызывать += на итераторах с произвольным доступом, код всегда не сможет скомпилироваться с обычным оператором if, даже с удалением мертвого кода. Потому что компилятор по-прежнему будет проверять синтаксис перед удалением кода. При использовании static if компилятор пропустит проверку синтаксиса, если условие не выполнено.

0 голосов
/ 07 декабря 2017
std::string a("hello world");
// bool a = true;
if(std::is_same<std::string, decltype(a)>::value) {
    std::string &la = *(std::string*)&a;
    std::cout << "std::string " << la.c_str() << std::endl;
} else {
    bool &la = *(bool*)&a;
    std::cout << "other type" << std::endl;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...