Как именно следует использовать declttype для вывода возвращаемого типа функции, которая возвращает экземпляр класса, инстанцированный по шаблону - PullRequest
0 голосов
/ 14 мая 2018

У нас есть базовая функция, которая добавляет 2 числа с плавающей точкой (с определенной степенью точности).

  float add(float x, float y)
  {
  std::cout << "\n in the add function \n";
  float res = x+y;
  std::cout << "\n exiting the add function \n";
  return res;
  }

У нас есть предварительное объявление

template <typename> struct Logger;

, за которым следует реализация,

template<typename R, typename... Args>
struct Logger<R(Args...)>
{
    // these  would be members 
  function<R(Args...)> func; 
  string name;

   // this would be ctor 
  Logger(const function<R(Args...)>& func, const string& name)
    :
      func{func},
      name{name}
  {

  }
    // this would be the overload fun operator 
  R  operator() (Args ...args) const 
  {
    cout << "\n Entering Into ... .......\n" << name << endl; 
    R result = func(args...); //  this would be actual call to the basic      function 
    cout << "\n Exiting from  ...  \n" << name << endl; 
    return result; //  this would be of type R, the return from the function call

  }
};

У нас есть функция,

// This function would provide an instantiation of 
// the Logger class, 
// and that would call the ctor of the Logger class 
template <typename R, typename... Args>
auto make_logger(R (*func)(Args...), const string& name ) 
{
  return Logger<R(Args...)>{

    std::function<R(Args...)>(func),
    name
  };

}
// Notice, there is no decltype in the above function, and I would like to use 
// the decltype, I am aware that decltype cannot be used on packed template argument

// Здесь используется API в некоторой основной функции

auto logger_add = make_logger(add, "**Adding Numbers**");
auto result = logger_add(2.0, 3.0);

Проблема:

Можно ли заставить приведенный выше код работать на C ++ 11?В частности, используя declytype, как можно использовать функцию make_logger.

Примечания: я слежу за книгой, а вышеприведенный код взят из https://github.com/Apress/design-patterns-in-modern-cpp/blob/master/Structural/Decorator/decorator.cpp

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Как указано в комментарии, вы уже указали тип, поэтому он будет

template <typename R, typename... Args>
auto make_logger(R (*func)(Args...), const string& name ) 
-> Logger<R(Args...)>
{
  return { std::function<R(Args...)>(func), name };
}

Демо

Лично я написал бы весь класс, что-то вроде:

template<typename F>
class Logger
{
private:
    F func; 
    std::string name;
public:
    Logger(const F& func, const std::string& name) :
      func{func},
      name{name}
    {}

    template <typename ... Args>    
    auto  operator() (Args&& ...args) const
    -> decltype(func(std::forward<Args>(args)...))
    {
        std::cout << "\n Entering Into ... .......\n" << name << std::endl;
        struct Finally {
            Finally(const std::string& name) : name(name) {}
            ~Finally() { std::cout << "\n Exiting from  ...  \n" << name << std::endl; }
            const std::string& name;
        } finally{name};
        return func(std::forward<Args>(args)...);
    }
};

template <typename F>
Logger<typename std::decay<F>::type>
make_logger(const F& func, const std::string& name)
{
  return { func, name };
}

Демо

0 голосов
/ 14 мая 2018

У вас были некоторые опечатки, не позволяющие вашему коду компилироваться как в C ++ 11, так и в C ++ 17. Следствием этой опечатки было R, которое должно быть выведено как тип функции вместо типа возврата;)

Исправлено:

template <typename R, typename... Args>
auto make_logger(R (*func)(Args...), const std::string& name )  -> Logger<R, Args...>
{
    return Logger<R, Args...> { std::function<R(Args...)>(func), name };
}

Полная демонстрация: http://coliru.stacked -crooked.com / a / 3e9e5cf6d29669c4

...