C++ 模板化类型特征类,其中模板参数引用正在定义的类型特征类

问题描述 投票:0回答:1

在下面的代码中,我使用类型特征类 Config 来参数化零成本抽象中使用的策略。 这可以正确编译并运行,但是如何使用要使用的策略模板化特征类?

namespace strategies {
    namespace initializers {
        template<typename Config> struct initializeA {
            constexpr   void operator()(typename Config::TEnvironment& v, double* weights) {
                for (int i = 0; i < v.ncols; i++) v.data[i] = weights[i];
                typename Config::Normalizer{}(v, v.data);
            }
        };
    }
    namespace updaters {
        template<typename Config> struct updaterA {
            constexpr   void operator()(typename Config::TEnvironment& v, double* weights) {
                for (int i = 0; i < v.ncols; i++) v.data[i] *= weights[i];
                typename Config::Normalizer{}(v, v.data);
            }
        };
    }
    namespace normalizers {
        template<typename Config> struct normalizerA {
            constexpr   void operator()(typename Config::TEnvironment& v, double* weights) {
                double sum = 0;
                for (int i = 0; i < v.ncols; i++) sum += weights[i];
                for (int i = 0; i < v.ncols; i++) weights[i] /= sum;
            }
        };
    }
}
template<int NCols> struct Environment {
    static const int ncols = NCols;
    double data[NCols];
};

template <typename TConfig>
class Runner {
public:
    typename TConfig::Environment env{};
    Runner() {}
    void doRun() {
        double weights[env.ncols];
        std::fill(weights, weights + env.ncols, 10.0);
        typename TConfig::Initializer{}(env, weights); //initialize & normalize env.data
        for (int i = 0; i < env.ncols; i++) weights[i] = (1 + i) / 10.0;
        typename TConfig::Updater{}(env, weights); //update & normalize env.data
    }
};

template<int NCols>
struct Config {
    using TEnvironment = Environment<NCols>;
    typedef TEnvironment Environment;
    typedef strategies::initializers::initializeA<Config> Initializer;
    typedef strategies::updaters::updaterA<Config> Updater;
    typedef strategies::normalizers::normalizerA<Config> Normalizer;
};
template<int NCols, typename InitializerT, typename UpdaterT, typename NormalizerT>
struct Config2 {
    using TEnvironment = Environment<NCols>;
    typedef TEnvironment Environment;
    typedef InitializerT Initializer; //strategies::initializers::initializeA<Config2> 
    typedef UpdaterT Updater; // strategies::updaters::updaterA<Config2>
    typedef NormalizerT Normalizer; // strategies::normalizers::normalizerA<Config2>
};

TEST_CLASS(ScratchTests) {
    TEST_METHOD(testScratch) {
        //this compiles & runs, specifying fixed types for Initializer/Updater directly inside Config
        Runner<Config<5>> runner{}; //instantiate with NCols = 5
        runner.doRun();
        Assert::IsTrue(runner.env.data[0] > 0.06 && runner.env.data[0] < 0.07);

        // how can I achieve the following, where the client specifies the types for Initializer/Updater/Normalizer, given these rely on TConfig to get the types of Normalizer?
        /*
        Runner<Config2<5, strategies::initializers::initializeA<Config2>, strategies::updaters::updaterA<Config2>, strategies::normalizers::normalizerA<Config2>> runner2{}; //instantiate with NCols = 5 and specify types for Initializer, Updater, Normalizer
        runner2.doRun();
        Assert::IsTrue(runner2.env.data[0] > 0.06 && runner2.env.data[0] < 0.07);
        */
    }
};

例如上面的特征类 Config2 之类的东西,但我不确定如何使用它,因为策略模板参数本身是使用配置类型进行模板化的,如上一个示例中给出的(Visual Studio 抱怨 Config2 参数缺少参数)初始化/更新器/标准化器)... 有没有办法使用某种中间 typedef?理想情况下使用 c++20,但开放到更高版本。

c++ templates design-patterns
1个回答
0
投票

你可以做

template<int NCols>
struct ConfigA : public Config2<NCols,
    strategies::initializers::initializeA<ConfigA<NCols>>,
    strategies::updaters::updaterA<ConfigA<NCols>>,
    strategies::normalizers::normalizerA<ConfigA<NCols>>>
{};

Runner<ConfigA<5>> runner2{};

演示

© www.soinside.com 2019 - 2024. All rights reserved.