使用函数参数作为模板参数

时间:2021-06-14 10:11:03

标签: c++ templates

template<unsigned int size>
struct Vec {
    Vec() = default;
};

auto build_vec(unsigned int size) {
    return Vec<size>();
}

int main() {
    auto vec = build_vec(5);
    return 0;
}

这个程序不能编译为 non-type template argument is not a constant expression。基本上,编译类型期间编译器不知道发送到 sizebuild_vec 参数。

那么我想知道,我可以添加一些关键字来强制在编译时评估 size 从而可以通过函数构建 struct Vec 吗?

3 个答案:

答案 0 :(得分:1)

不,这是不可能的。函数参数在编译时未知。表示 size 必须在编译时已知的常用方法是将函数设为模板,将 size 设为模板参数:

template<unsigned int size>
struct Vec {
    Vec() = default;
};

template <unsigned int size>
auto build_vec() {
    return Vec<size>();
}

int main() {
    auto vec = build_vec<5>();
}

不过,现在应该很明显该函数并不能帮助将运行时值转换为编译时值。通常这是不可能的,除非您手动实现此类映射。您不需要 build_vec,因为调用者可以直接使用 auto vec = Vec<size>();

答案 1 :(得分:1)

它不完全符合您的期望,但依赖于我们可能有类似的 boost hana 方法。下面是一个使用变量模板的例子

#include <iostream>

template<unsigned int size>
struct Vec {
    Vec() = default;
    ~Vec() {std::cout << size << '\n';}
};


template <unsigned int i>
constexpr std::integral_constant<unsigned int, i> uint_c{};

template <unsigned int i>
auto build_vec(std::integral_constant<unsigned int, i>) {
    return Vec<i>();
}

int main() {
    const size_t n = 5;
    auto vec = build_vec(uint_c<n>);
    return 0;
}

答案 2 :(得分:0)

<块引用>

我的代码库限制我它必须是函数参数,而不是模板参数。

这不可能。函数的返回类型不能依赖于运行时值。您的选择是:

  1. 也将 Vec 的模板参数设为运行时值。
  2. 如果可能的运行时值集很小,您可以生成编译时所需的所有代码,并使用一些运行时分支来确定要使用的内容。返回类型不能依赖于此,因此您可以返回类型擦除的对象(std::any 等),让 Vec 类派生自某个基类,或者不返回该对象。如果范围太大,请不要这样做。它可能generate大量代码膨胀:
#include <cstdio>
#include <utility>

template <unsigned size>
struct Vec {
  Vec() = default;
  void use_value() { std::printf("My constexpr value is %u\n", size); }
};

template <unsigned ct_val>
void build_vec_impl_impl() {
  Vec<ct_val> cant_return;
  cant_return.use_value();
}

template <unsigned... vals>
void build_vec_impl(std::integer_sequence<unsigned, vals...>, unsigned rt_val) {
  using fp_builder = void (*)();

  constexpr fp_builder builders[]{build_vec_impl_impl<vals>...};
  builders[rt_val]();
}

template <unsigned max>
void build_vec(unsigned const rt_val) {
  using seq = std::make_integer_sequence<unsigned, max + 1>;
  build_vec_impl(seq{}, rt_val);
}

int main() {
  auto constexpr max = 10;
  for (unsigned i = 0; i < max; ++i) build_vec<max>(i);
}

3.使用像 Python 这样的动态语言,其中返回类型可能取决于运行时值