You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++模板类构造函数中分发多参数包初始化多个仿函数?

问题:直接通过Composer构造函数完成三个仿函数的初始化

现有一段无法正常运行的C代码,目标是实现一个Composer模板类,串联三个仿函数(StageOne、StageTwo、StageThree),并希望直接通过Composer的构造函数完成这三个仿函数的初始化,而非额外调用setStageOne这类方法。原代码的问题在于构造函数的模板参数包写法不符合C推导规则,导致无法编译。

原代码如下:

#include<iostream>

template<typename T1, typename T2, typename T3>
class Composer {
    // pseudocode of constructor
    template<typename... Args_one, typename... Args_two, typename... Args_three>
    explicit Composer(Args_one...args1, Args_two...args2, Args_three...args3) {
        t1_ = T1(args1...);
        t2_ = T2(args2...);
        t3_ = T3(args3...);
    }

    double operator()(int u) {
        auto x1 = t1_(u);
        auto x2 = t2_(float(x1));
        auto x3 = t3_(double(x2));
        return x3;
    }
private:
    T1 t1_;
    T2 t2_;
    T3 t3_;
};

class StageOne {
public:
    StageOne(int a, int b): a_(a), b_(b) {};
    int operator()(int c) const {
        return a_ + b_ + c;
    }
private:
    int a_;
    int b_;
};

class StageTwo {
public:
    StageTwo(float c, float d): c_(c), d_(d) {};
    float operator()(float i) const {
        return c_ + d_ + i;
    }
private:
    float c_;
    float d_;
};

class StageThree {
public:
    StageThree(double x, double y): x_(x), y_(y) {};
    double operator()(double z) const {
        return (x_  + y_) * z;
    }
private:
    double x_;
    double y_;
};

int main()
{
    Composer<StageOne, StageTwo, StageThree> composer{{3, 4}, {1.2f, 2.3f}, {4.5, 3.3}};
    std::cout << composer(3) << std::endl;
}

可行解决方案

方案一:直接接受已构造的仿函数对象

最简单的方式是让Composer的构造函数直接接收三个已经初始化好的T1、T2、T3对象,语法合规且直观:

#include<iostream>
#include<utility>

template<typename T1, typename T2, typename T3>
class Composer {
public:
    explicit Composer(T1 t1, T2 t2, T3 t3) 
        : t1_(std::move(t1)), t2_(std::move(t2)), t3_(std::move(t3)) {}

    double operator()(int u) {
        auto x1 = t1_(u);
        auto x2 = t2_(static_cast<float>(x1));
        auto x3 = t3_(static_cast<double>(x2));
        return x3;
    }
private:
    T1 t1_;
    T2 t2_;
    T3 t3_;
};

// StageOne、StageTwo、StageThree类保持不变

int main()
{
    Composer<StageOne, StageTwo, StageThree> composer(
        StageOne(3, 4),
        StageTwo(1.2f, 2.3f),
        StageThree(4.5, 3.3)
    );
    std::cout << composer(3) << std::endl;
}

方案二:用tuple包裹构造参数并展开

如果希望直接传入构造参数而非提前构造Stage对象,可以用std::tuple包裹每个Stage的参数,再通过std::apply展开初始化成员:

#include<iostream>
#include<tuple>
#include<utility>

template<typename T1, typename T2, typename T3>
class Composer {
public:
    template<typename... Args1, typename... Args2, typename... Args3>
    explicit Composer(std::tuple<Args1...> args1, std::tuple<Args2...> args2, std::tuple<Args3...> args3)
        : t1_(std::apply([](auto&&... args){ return T1(std::forward<decltype(args)>(args)...); }, std::move(args1))),
          t2_(std::apply([](auto&&... args){ return T2(std::forward<decltype(args)>(args)...); }, std::move(args2))),
          t3_(std::apply([](auto&&... args){ return T3(std::forward<decltype(args)>(args)...); }, std::move(args3)))
    {}

    double operator()(int u) {
        auto x1 = t1_(u);
        auto x2 = t2_(static_cast<float>(x1));
        auto x3 = t3_(static_cast<double>(x2));
        return x3;
    }
private:
    T1 t1_;
    T2 t2_;
    T3 t3_;
};

// StageOne、StageTwo、StageThree类保持不变

int main()
{
    Composer<StageOne, StageTwo, StageThree> composer(
        std::make_tuple(3, 4),
        std::make_tuple(1.2f, 2.3f),
        std::make_tuple(4.5, 3.3)
    );
    std::cout << composer(3) << std::endl;
}

方案三:利用聚合初始化(C++17及以上)

将Composer改为聚合类(无用户声明构造函数、非静态成员均为public),可直接用聚合初始化语法完成成员初始化:

#include<iostream>

template<typename T1, typename T2, typename T3>
class Composer {
public:
    double operator()(int u) {
        auto x1 = t1_(u);
        auto x2 = t2_(static_cast<float>(x1));
        auto x3 = t3_(static_cast<double>(x2));
        return x3;
    }

    T1 t1_;
    T2 t2_;
    T3 t3_;
};

// StageOne、StageTwo、StageThree类保持不变

int main()
{
    Composer<StageOne, StageTwo, StageThree> composer{
        StageOne(3, 4),
        StageTwo(1.2f, 2.3f),
        StageThree(4.5, 3.3)
    };
    std::cout << composer(3) << std::endl;
}

原代码编译失败原因

原构造函数的写法违反C++模板推导规则:模板参数包只能放在函数参数列表的最后一位,编译器无法区分args1、args2、args3的参数边界,因此无法推导三个参数包的类型和数量,导致编译失败。

内容的提问来源于stack exchange,提问作者H. Yong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:55:07