c++ - 我们可以在 constexpr 函数中创建一个指向对象的指针的 std::array 并返回它吗?
问题描述
假设我们有某种模板结构:
template<typename T>
struct S {};
我们想创建一个 S 类型对象的 std::array。但是,因为 S 是一个模板结构,我们需要创建一个基类来保存这些对象。
struct AbstractS {};
template<typename T>
struct S : AbstractS {};
现在,假设我们有一个创建 std::array 并返回它的 constexpr 函数和一个用于获取该数组的 constexpr 函数。
constexpr auto createArray() {
constexpr auto v1 = S<int>{};
constexpr auto v2 = S<double>{};
std::array<const AbstractS *, 2> values{ &v1, &v2 };
return values;
}
constexpr void getArray() {
constexpr auto values = createArray();
}
此代码无法编译,我认为这是因为 v1 和 v2 的地址不是常量。
让我给你一个具体的例子来说明我正在尝试做的事情。
struct AbstractPolynomial {};
template<typename T, std::size_t Degree>
struct Polynomial : AbstractPolynomial {};
我有一个对多项式函数进行建模的结构,其中 T 是多项式系数的值的类型,而度数是多项式度数。
template<std::size_t N>
constexpr auto createArray() {
std::array<AbstractPolynomial *, N> polynomials;
for (std::size_t i = 0; i < N; i++) {
if (i % 2 == 0) {
polynomials[i] = &Polynomials<T1>{5};
} else {
polynomials[i] = &Polynomials<T2>{2, 5};
}
}
return polynomials;
}
假设多项式有一个推导指南(我这里没有实现)。我知道您无法获得临时地址并且分配线路不正确,但我输入此表格是因为我希望您为我提供此方案的解决方案。
我们可以做一些技巧来创建这样的场景吗?
解决方案
这是解决方案,请注意,多项式需要在最初生成时保留其编译时类型。出于任何原因(动态访问)不使用该信息的后一种选择是您的。
注意数据结构是 constexpr,但不一定是多项式的求值。我认为这是因为virtual
干扰了函数的constexpr
-ness 能力。evaluate
您可以在此处使用解决方案:https ://godbolt.org/z/oMreTzoGP
#include<array>
#include<cassert>
#include<tuple>
#include<utility>
// Dynamic polymials (questionable use of virtual functions)
struct AbstractPolynomial {
virtual auto evaluate() const -> double = 0;
};
template<typename T>
struct Polynomial : AbstractPolynomial {
constexpr Polynomial(T t) : value_{t}{}
T value_;
auto evaluate() const -> double override;
};
// instantiate and define two child classes for illustration
template<> auto Polynomial<double >::evaluate() const -> double {return value_;}
template<> auto Polynomial<std::pair<double, double>>::evaluate() const -> double {return value_.first + value_.second;}
// Metaprogramming in this block doesn't assume virtual functions, Polynomial can be a concrete class
// functional form (on index and constructor args) taken from OP example
constexpr auto makePoly(std::integral_constant<int, 0>){return Polynomial<double >{5.};}
constexpr auto makePoly(std::integral_constant<int, 1>){return Polynomial<std::pair<double, double>>({2., 5.});}
// Tuples (not arrays) are created here
template <std::size_t... I>
constexpr auto createTuple_aux(std::index_sequence<I...>){
// do different things for even/odd cases (again taken from OP example)
return std::make_tuple(makePoly(std::integral_constant<int, I % 2>{})...);
}
template <std::size_t N> constexpr auto createTuple(){return createTuple_aux(std::make_index_sequence<N>{});}
// create 10 non-polymorphic polynamials in a tuple (preserve type information)
constexpr auto polyTuple = createTuple<10>();
// create 10 polymorphic polynamials in an array via pointers (type information is kept in the virtual table in pointer elements)
constexpr auto polyArrayPtr = std::apply([](auto const&... e){return std::array<AbstractPolynomial const*, std::tuple_size<decltype(polyTuple)>{}>{&e...};}, polyTuple);
int main(){
// test non-polymorphic access
assert( std::get<0>(polyTuple).evaluate() == 5. );
assert( std::get<1>(polyTuple).evaluate() == 7. );
assert( std::get<2>(polyTuple).evaluate() == 5. );
// test polymorphic access, indiraction
constexpr auto check = polyArrayPtr.size();
assert( polyArrayPtr[0]->evaluate() == 5. );
assert( polyArrayPtr[1]->evaluate() == 7. );
assert( polyArrayPtr[2]->evaluate() == 5. );
}
推荐阅读
- tcp - 如何在 GNS3 中模拟 Modbus 流量?
- ios - 将构成我的应用程序数据模型的数组变量放在哪里最好?
- excel - VBA 将 Webbrowser 置于 Office2019 中的用户窗体之外
- oracle - 光标/批量收集
- python - Python如何计算两个数组中特定值的交集?
- c# - 如何有效区分 Unity 中的点击和滑动?
- php - 如何在 Laravel 中插入一对多关系
- angular - 如何为 ag-grid 过滤器提供默认值
- python-3.x - web2py-sqlform 无法检查与 requires=IS_LENGTH() 一起使用的 unique=True
- javascript - JavaScript函数参数问题:没有参数的情况下如何使用参数?