constexpr参数化的函数指针

时间:2019-01-23 14:50:11

标签: c++ lambda c++17 constexpr

我具有以下第三方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的方式。

3 个答案:

答案 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"_udlX<'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>());