2

I know I need a template keyword when calling a template method of a template in a depended context. This is quite clear to me.

Now, I have something like:

#include <repository/RepositoryManager.hpp>
#include <events/Manager.hpp>
#include <memory>
#include <boost/di.hpp>

namespace di = boost::di;

inline std::shared_ptr<RepositoryManager> createRepositoryManager(int p) {
  (void)p;
  auto injector = di::make_injector(
      di::bind<events::Manager>().to<events::Manager>().in(di::singleton)
  );
  return injector.create<std::shared_ptr<RepositoryManager>>();
}

This compiles and works as expected but what I actually need is it to be a template but simply changing the definition like this:

template <typename Param>
inline std::shared_ptr<RepositoryManager> createRepositoryManager(Param p)

Gives me a bunch of errors:

In file included from x/main.cpp:7:0:
x/setup.hpp: In function ‘std::shared_ptr<RepositoryManager> createRepositoryManager(Param)’:
x/setup.hpp:19:53: error: expected primary-expression before ‘>’ token
       di::bind<events::Manager>().to<events::Manager>().in(di::singleton)
                                                     ^
x/setup.hpp:19:55: error: expected primary-expression before ‘)’ token
       di::bind<events::Manager>().to<events::Manager>().in(di::singleton)
                                                       ^
x/setup.hpp:21:59: error: expected primary-expression before ‘>’ token
   return injector.create<std::shared_ptr<RepositoryManager>>();
                                                           ^~
x/setup.hpp:21:62: error: expected primary-expression before ‘)’ token
   return injector.create<std::shared_ptr<RepositoryManager>>();
                                                              ^

I have figured out I can change the definition like this and all is good:

template <typename Param>
inline std::shared_ptr<RepositoryManager> createRepositoryManager(Param p) {
  (void)p;
  auto injector = di::make_injector(
      di::bind<events::Manager>().template to<events::Manager>().in(di::singleton)
  );
  return injector.template create<std::shared_ptr<RepositoryManager>>();
}

I'd like, however, to understand why. The events::Manager and RepositoryManager are normal classes (complete, not templates). I don't see how I could be in a dependent context here unless there's some funny rule I do not understand.

Oh, and just out of curiosity I've tried the code below and it also compiles. I'm lost.

template <typename Param>
inline std::shared_ptr<RepositoryManager> createRepositoryManager(Param p) {
  (void)p;
  auto injector = di::make_injector();
  return injector.create<std::shared_ptr<RepositoryManager>>();
}

Edit:

It has been marked as duplicate of: Where and why do I have to put the "template" and "typename" keywords? Well, I've read that before asking and it still does not explain my situation (unless I'm really missing something). Neither template parameter type, nor parameter value is used here, so my understanding is I'm in an independent context and I should be able to call the templated methods just fine. So where am I wrong?

Jakub
  • 33
  • 5
  • What compiler and version? – Ben Voigt Apr 07 '18 at 19:01
  • I'm on GCC-7.3 with C++17. From some other error messages I suspect the DI library is doing some magic with generic lambdas and if I understand correctly, that is what makes the injector type a dependent type. – Jakub Apr 08 '18 at 20:47
  • Well it would be interesting to know whether using a simple class with nested template acts differently from the whole DI infrastructure in terms of this keyword. – Ben Voigt Apr 08 '18 at 21:02

0 Answers0