我正在写一个库,其中使用非类型模板参数将本质上是静态的对象参数内置到类型中。在这些值是运行时值的实施中,这样做可以提供大量性能优化(小型基准测试为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
函数不起作用,宏不适用于类型系统,因此它们也不足,我该怎么办?
答案 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'}