constexpr 参数化函数指针
constexpr parametrized function pointer
我有以下第三方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 解决方案。
将字符串作为模板参数传递似乎也是一种选择:
,但我很好奇是否有 constexpr
的方法。
有点。
这个:
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 中,我们将能够编写一个 class 类型,其模板参数是一个固定字符串,这将允许 getHistogramLambda<"obj1">
工作,只是方式略有不同。
到那时,目前最好的方法可能是使用 UDL 捕获单个字符作为某些 class 类型的模板参数:
template <char... Cs>
constexpr auto getHistogramLambda(X<Cs...>) {
static constexpr char name[] = {Cs..., '[=13=]'};
return [](const auto& v) { return histogram(name, v);};
}
obj->ComputeStatistic(getHistogramLambda("obj1"_udl));
这里的意图是 "obj"_udl
是类型 X<'o', 'b', 'j', '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>());
不同的答案,由 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 方法更好,但这肯定是一种有趣的技术。
我有以下第三方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 解决方案。
将字符串作为模板参数传递似乎也是一种选择:
,但我很好奇是否有 constexpr
的方法。
有点。
这个:
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 中,我们将能够编写一个 class 类型,其模板参数是一个固定字符串,这将允许 getHistogramLambda<"obj1">
工作,只是方式略有不同。
到那时,目前最好的方法可能是使用 UDL 捕获单个字符作为某些 class 类型的模板参数:
template <char... Cs>
constexpr auto getHistogramLambda(X<Cs...>) {
static constexpr char name[] = {Cs..., '[=13=]'};
return [](const auto& v) { return histogram(name, v);};
}
obj->ComputeStatistic(getHistogramLambda("obj1"_udl));
这里的意图是 "obj"_udl
是类型 X<'o', 'b', 'j', '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>());
不同的答案,由 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 方法更好,但这肯定是一种有趣的技术。