在下面的代码中,我使用类型特征类 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,但开放到更高版本。
你可以做
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{};