使用非constexpr对象的静态constexpr成员变量作为模板参数

时间:2019-11-07 22:13:29

标签: c++ templates constexpr

我正在写一个库,其中使用非类型模板参数将本质上是静态的对象参数内置到类型中。在这些值是运行时值的实施中,这样做可以提供大量性能优化(小型基准测试为10倍,预期为5-7倍)。但是,我发现C ++不能很好地支持这种习惯用法。我正在尝试重构该库,以使对模板或元编程不太熟悉的开发人员可以更轻松地使用它。

我想提供constexpr函数,简化对static constexpr成员变量(用于通过类型传播静态值)的提取,以便用户执行一些基本的元编程,而无需了解幕后的重型机械。例如,

#include <type_traits>


template <int A, int B>
class Example {
public:
    static constexpr auto C = A + B;
private:
    int b {0};
};

template <int A, int B>
constexpr auto getC(Example<A, B> e) { return decltype(e)::C; }

/**** USER CODE ****/

int main()
{
    Example<1, 2> e;
    Example<2, getC(e)> f;
}

这不起作用,即使您不使用该值,也可以在constexpr上下文中使用e作为非constexpr(奇怪的是,如果Example没有运行时成员,它将起作用)。可以改写decltype(e)::C,但是如果要作为参考,他们将不得不std::remove_reference<decltype(C)>::type::C,并且他们当然必须知道要这样做,并且要有足够的知识来解决诸如{{1} }。到那时,对于该库适用于的典型程序员,我们已经步步为营。

remove_reference函数不起作用,宏不适用于类型系统,因此它们也不足,我该怎么办?

2 个答案:

答案 0 :(得分:1)

您可以使用宏来包装

std::remove_reference<decltype(C)>::type::C

看起来像

#define getC(obj) std::remove_reference_t<decltype(obj)>::C

答案 1 :(得分:1)

为了实现getC,我选择了内森答案和已删除答案的组合。

template <typename T, typename = std::void_t<decltype(std::remove_reference_t<T>::C)>>
constexpr int getC_() { return std::remove_reference_t<T>::C; }

#define getC(e) (getC_<decltype(e)>())

如果您给无效的类型提供了保护,则该函数可以完成繁重的工作,并给出良好的错误消息。宏以一种永远不会失败的方式进行混乱的(对初学者而言)调用。

getC(1);  // error: 'C' is not a member of 'std::remove_reference<int>::type' {aka 'int'}