我具有以下第三方API:
using StatisticsFunc = double (*)(const std::vector<double> &)
libraryClass::ComputeStatistics(StatisticsFunc sf);
我正在这样使用:
obj1->ComputeStatistics([](const auto& v) {return histogram("obj1", v);};
obj2->ComputeStatistics([](const auto& v) {return histogram("obj2", v);};
但是所有这些lambda只是重复的代码。我宁愿这样:
obj1->ComputeStatistics(getHistogramLambda("obj1"));
所以我需要定义:
constexpr auto getHistogramLambda(const char* name) {
return [](const auto& v) {return histogram(name, v);};
}
但是它不起作用,因为未捕获name
。也不行:
constexpr auto getHistogramLambda(const char* name) {
return [name](const auto& v) {return histogram(name, v);};
}
因为捕获lambda不再不是无状态的,并且不能转换为函数指针。
Ofc可以将其作为宏来完成,但是我想要一种现代的C ++ 17解决方案。
将字符串作为模板参数传递似乎也是一种选择:
https://stackoverflow.com/a/28209546/7432927,但我很好奇是否有一种constexpr
的方式。
答案 0 :(得分:2)
排序。
此:
obj1->ComputeStatistics(getHistogramLambda("obj1"));
由于您指出的原因而无法使用-您需要捕获状态。然后,我们不能这样写:
obj1->ComputeStatistics(getHistogramLambda<"obj1">());
因为我们可以使用const char*
类型的模板参数,但不能将它们绑定到字符串文字。您可以这样做:
template <const char* name>
constexpr auto getHistogramLambda() {
return [](const auto& v) {return histogram(name, v);};
}
const char p[] = "obj1";
obj1->ComputeStatistics(getHistogramLambda<p>());
这很尴尬,因为您需要为每次调用引入额外的变量。在C ++ 20中,我们将能够编写一个具有固定字符串作为其模板参数的类类型,该类类型将允许getHistogramLambda<"obj1">
以一种稍有不同的方式工作。
直到那时,目前最好的方法可能是使用UDL捕获单个字符作为某些类类型的模板参数:
template <char... Cs>
constexpr auto getHistogramLambda(X<Cs...>) {
static constexpr char name[] = {Cs..., '\0'};
return [](const auto& v) { return histogram(name, v);};
}
obj->ComputeStatistic(getHistogramLambda("obj1"_udl));
这里的意图是"obj"_udl
是X<'o', 'b', 'j', '1'>
类型的对象-然后我们以不需要捕获的方式在函数模板的主体内重建字符串。
这样做是否值得避免重复?也许。
答案 1 :(得分:0)
由Michael Park提供不同的答案。我们可以将所需的值编码为一种类型-无需将所需的字符串文字作为函数参数或模板参数传递,而是作为实际类型传递-这样我们就无需捕获它:
#define CONSTANT(...) \
union { static constexpr auto value() { return __VA_ARGS__; } }
#define CONSTANT_VALUE(...) \
[] { using R = CONSTANT(__VA_ARGS__); return R{}; }()
template <typename X>
constexpr auto getHistogramLambda(X) {
return [](const auto& v) { return histogram(X::value(), v);};
}
obj->ComputeStatistic(getHistogramLambda(CONSTANT_VALUE("obj1")));
obj->ComputeStatistic(getHistogramLambda(CONSTANT_VALUE("obj2")));
不确定在特定情况下这比UDL方法要好,但是可以肯定,这是一种有趣的技术。
答案 2 :(得分:-1)
不确定是否真正需要什么,但是...声明一个constexpr
个指针的全局char const
数组又如何呢?
constexpr std::array<char const *, 3u> arrStr {{"obj0", "obj1", "obj2"}};
然后在getHistogramLambda()
中接收所需字符串的索引作为模板参数?
template <std::size_t N>
constexpr auto getHistogramLambda () {
return [](const auto& v) {return histogram(arrStr.at(N), v);};
}
这样,您可以按以下方式致电ComputeStatistic()
obj1->ComputeStatistics(getHistogramLambda<1u>());