C++ - 可变参数函数的多个参数包

C++ - Multiple parameter packs for variadic function

我是 c++ 的新手,对于我的第一个项目,我正在尝试编写一个 ioc 容器,通过向注册函数添加可变参数来扩展 this blog post 中描述的概念。因此,一个参数包将用于可变参数,另一个参数包用于声明要注册的类型的依赖关系。

阅读了一些内容后,我发现了一些类似于我最终尝试做的事情。该函数如下所示:

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;
}

我用 iocContainer_.RegisterSingletonClassFactory<boost::asio::io_context, std::tuple<>>(30); 来称呼它。

然而,这给了我错误“错误:没有匹配的函数调用”... clang 告诉我“候选模板被忽略:明确无效-为模板参数指定参数 'TUnused'".

有办法吗?错误的确切含义是什么?

谢谢

And what exactly does the error mean?

错误意味着你的电话

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

与您的模板函数的声明不匹配

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

因为您的模板函数等待

  1. 类型参数(T),

  2. 一个模板-模板参数(TUnused)

和其他模板参数当你传递

  1. 类型参数 (boost::asio::io_context)

  2. 另一个类型模板参数(std::tuple<>)

如果您想将 std::tuple 作为模板-模板参数传递,则必须在不传递模板参数的情况下传递它(std::tuple,而不是 std::tuple<>)。

鉴于您的 TUnused 参数是...好吧,未使用...我想您的意图是将其用作类型容器。

但是没有这个必要

不确定,但在我看来,您正在寻找类似的东西

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

所以你可以显式 T 和一个(可能是空的)TDependecies... 类型列表。

TArgs... 列表是从参数推导出来的

以下是一个愚蠢的编译 C++17 示例

#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);   
 }

其中Tstd::string(第一个显式模板参数),TDependencies...short, int, long, long long(后面的显式模板参数),TArgs...int, long, long long(从 0, 1l, 2ll 参数推导出来)。

注意您不需要 TUnused 模板参数。

现在很清楚 std::tuple 在原始问题中并不是真正需要的,但是为了完整起见,让我举一个例子说明如何从 std::tuple 中提取 Dependencies-喜欢类型1。我们所需要的只是一个额外的间接级别:

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...);
}

现在

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

将调用 RegisterSingletonClassFactoryImpl()Dependencies 包为 A, B, C


1 任何其他类型列表

template<class...>
class type_list;

可以用来代替std::tuple