带有两个(或更多)特定包(专业化/重载)的可变参数函数模板

non*_*741 5 c++ variadic-functions overload-resolution variadic-templates c++17

函数“Process”正在接受可变数量的变量类型参数。为了处理不同的情况,我已经成功地像这样重载了它:

// general case
template <typename ...Types>
void Process( const Types&... items )

// single T
template <typename T>
void Process( const T& t )

// one or more of type NVP<>
template <typename T1, typename ...Types>
void Process( const NVP<T1>& nvp1, const NVP<Types>&... nvps )
Run Code Online (Sandbox Code Playgroud)

我想要做的 - 但不能 - 如下:对于具有任意数量的类型的前导参数ATT<>后跟任意数量的情况,我需要重载NVP<>:

// any number of leading Types ATT<> followed by any number of NVP<>
template <typename ...ATypes, typename ...BTypes>
void Process( const ATT<ATypes>&... atts, const NVP<BTypes>&... nvps )
Run Code Online (Sandbox Code Playgroud)

起初你会认为编译器匹配它应该是“容易”的,如果它已经可以完成其他情况。这里应该绝对没有歧义!?但是,匹配失败,没有错误消息,但是编译器忽略了所需的重载。

目前使用 VS2017 和 /std:c++17


笔记:

1.它可以,很明显,被用于做一个领导型ATT<T1>这样的

// one leading Type ATT<T1>
template <typename T1, typename ...Types>
void Process( const ATT<T1>& a1, const Types&... remaining )
Run Code Online (Sandbox Code Playgroud)

但是对于不止一个,我需要做一些丑陋的手动递归。我真的很想拥有一整套领先的ATT<...>.

2.我知道一个领先的参数包——一般类型——对于匹配总是不明确的,但对于像ATT<ATypes>...不存在歧义这样的专业化。

小智 0

相信您可以使用结构来帮助您。编译器无法确定一个参数包在哪里停止而另一个参数包从哪里开始,请考虑:

foo(1, 2.0, '3', "45", 6.0f)。第一个参数包可以什么都没有,第一个,所有这些,或者以上都不是。没有特别的理由更喜欢其中一种。所以你不能创建一个接受两个变量的函数。您可以做的是将其分成两个结构,并显式指定外部类的参数。

template<typename... Args>
struct S
{
    template<typename... Inner>
    static void Process(const ATT<Args>&... atts, const NVP<Inner>&... nvps) {}
};
Run Code Online (Sandbox Code Playgroud)

使用示例:

ATT<double> a1;
ATT<long> a2;
NVP<int> n1;
NVP<const char*> n2;

S<double, long>::Process(a1, a2, n1, n2);
Run Code Online (Sandbox Code Playgroud)

另一个版本可以使用构造函数。在这里,您还可以获得自动扣除,这更容易。不幸的是,它仅适用于 C++17 及更高版本。

template<typename... Args>
struct S
{
    std::tuple<ATT<Args>...> tup;

    S(const ATT<Args>&... atts)
        : tup(atts...)
    {}

    template<typename... Inner>
    void Process(const NVP<Inner>&... nvps){}
};

template<typename... Args>
S(const ATT<Args>&... atts)->S<Args...>;
Run Code Online (Sandbox Code Playgroud)

用法是:

S(ATT(1), ATT(3.4)).Process(NVP("asdf"), NVP(3.4), NVP('f'));
return 0;
Run Code Online (Sandbox Code Playgroud)