简体   繁体   中英

C++ - Multiple parameter packs for variadic function

I am pretty new to c++ and for my first project am trying to write an ioc container expanding the concept described in this blog post by adding variadic arguments to the registering functions. So one parameter pack would be used for variadic arguments and the other one to declare the dependencies of the type to register.

After reading a bit I came across stuff similar to what I tried to do in the end. The function looks like this:

template <class T,
        template<typename ...TDependencies> typename TUnused, typename... TDependencies,
        typename ...TArgs>
void RegisterSingletonClassFactory(TArgs...args)
{
    std::string typeKey = typeid(T).name();
    creatorMap_[typeKey] = [this, args...](){
        return new T(GetInstance<TDependencies>()..., args...);
    };

    std::shared_ptr<IHolder> iHolder = instanceMap_[typeKey];
    auto * holder = dynamic_cast<Holder<T>*>(iHolder.get());
    if(holder != nullptr)
        holder->instance_ = nullptr;
}

And I call it with iocContainer_.RegisterSingletonClassFactory<boost::asio::io_context, std::tuple<>>(30);.

This however gives me the error " error: no matching function for call to "... with clang telling me " candidate template ignored: invalid explicitly-specified argument for template parameter 'TUnused' ".

Is there a way to do this? And what exactly does the error mean?

Thanks

And what exactly does the error mean?

The error mean that your call

iocContainer_.RegisterSingletonClassFactory<boost::asio::io_context, std::tuple<>>(30);

doesn't matches the declaration of your template function

template <class T,
        template<typename ...TDependencies> typename TUnused, typename... TDependencies,
        typename ...TArgs>
void RegisterSingletonClassFactory(TArgs...args)

because your template functions waits for

  1. a type parameter ( T ),

  2. a template-template parameter ( TUnused )

and other template parameters when you pass

  1. a type paramer ( boost::asio::io_context )

  2. another type template parameter ( std::tuple<> )

If you want to pass std::tuple as template-template parameter, you have to pass it without template parameters ( std::tuple , not std::tuple<> ).

Given that your TUnused parameter is... well, unused,... I suppose that your intention was to use it as type container.

But there is no needs for it.

Not sure but seems to me that your looking for something similar

template <typename T, typename... TDependencies, typename ...TArgs>
void foo (TArgs...args)

So you can explicit T and a (maybe empty) TDependecies... list of types.

The TArgs... list is deduced from the arguments

The following is a silly, but compiling, C++17 example

#include <iostream>

template <typename T, typename... TDependencies, typename ...TArgs>
void foo (TArgs...args)
 {
   std::cout << "T:" << typeid(T).name() << std::endl;

   std::cout << "TDependecies list:" << std::endl;

   ((std::cout << "- " << typeid(TDependencies).name() << std::endl), ...);

   std::cout << "TArgs list:" << std::endl;

   ((std::cout << "- " << typeid(TArgs).name() << std::endl), ...);
 }

int main()
 {
   foo<std::string, short, int, long, long long>(0, 1l, 2ll);   
 }

where T is std::string (the first explicit template parameters), TDependencies... is short, int, long, long long (the following explicit template parameters) and TArgs... is int, long, long long (deduced from the 0, 1l, 2ll arguments).

Observe that you don't need the TUnused template parameter.

It is clear now that std::tuple was not really needed in the original problem, but for completeness let me give an example of how Dependencies could be extracted from the std::tuple -like types 1 . All we need is an additional level of indirection:

template<class T>
struct wrapper {};

template<class T, template<class...> class Unused, 
         class... Dependencies, class... Args>
void RegisterSingletonClassFactoryImpl(
    wrapper<Unused<Dependencies...>>, Args... args) {

    std::string typeKey = typeid(T).name();
    creatorMap_[typeKey] = [this, args...]() {
        return new T(GetInstance<Dependencies>()..., args...);
    }; 
    // ...
}

template<class T, class Unused, class... Args>
void RegisterSingletonClassFactory(Args... args) {
    RegisterSingletonClassFactoryImpl<T>(wrapper<Unused>{}, args...);
}

Now

RegisterSingletonClassFactory<T, std::tuple<A, B, C>>()

will call RegisterSingletonClassFactoryImpl() with Dependencies pack being A, B, C .


1 Any other type list

template<class...>
class type_list;

can be used instead of std::tuple .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM