无法推断模板参数,即使在编译时已知



我有一个可变模板类SomeClass,看起来像这样(基本上):

template<std::size_t SIZE_>
class SomeClass {
public:
static constexpr std::size_t SIZE = SIZE_;
};

它有一个constexpr成员,该成员只包含用于实例化它的std::size_t模板形参。我想要一个constexpr函数,它可以求和所有SomeClass<SIZE_>专门化的大小。我的第一个想法是做一个简单的可变模板函数,添加所有的SIZE,像这样:

template<typename T>
constexpr std::size_t totalSize() {
return T::SIZE;
}
template <typename T, typename... Ts>
constexpr std::size_t totalSize() {
return totalSize<T>() + totalSize<Ts...>();
}

现在我试着叫它:

constexpr std::size_t size = totalSize<SomeClass<1>, SomeClass<2>, SomeClass<3>>()    // should return 6

最后一个参数解包使得对totalSize<T>函数的调用有歧义,因为两个模板totalSize函数都匹配它。好吧,我修改了我的代码,使其具有两个不同的函数,并提出了这个:

template<typename T>
constexpr std::size_t totalSizeSingle() {
return T::SIZE;
}
template <typename T, typename... Ts>
constexpr std::size_t totalSize() {
std::size_t result = totalSizeSingle<T>();
if (sizeof...(Ts) > 0) result += totalSize<Ts...>();
return result;
}

再一次,最后一次拆包似乎有问题。显然,即使在编译时知道T,也不能推导出来。我得到以下错误(使用GCC编译):

In instantiation of 'constexpr std::size_t totalSize() [with T = SomeClass<3>; Ts = {}; std::size_t = long long unsigned int]':
main.cpp:129:51:   required from here
main.cpp:134:82:   in 'constexpr' expansion of 'totalSize<SomeClass<1>, SomeClass<2>, SomeClass<3> >()'
main.cpp:129:51:   in 'constexpr' expansion of 'totalSize<SomeClass<2>, SomeClass<3> >()'
main.cpp:129:58: error: no matching function for call to 'totalSize<>()'
129 |         if (sizeof...(Ts) > 0) result += totalSize<Ts...>();
|                                          ~~~~~~~~~~~~~~~~^~
main.cpp:127:23: note: candidate: 'template<class T, class ... Ts> constexpr std::size_t totalSize()'
127 | constexpr std::size_t totalSize() {
|                       ^~~~~~~~~
main.cpp:127:23: note:   template argument deduction/substitution failed:
main.cpp:129:58: note:   couldn't deduce template parameter 'T'
129 |         if (sizeof...(Ts) > 0) result += totalSize<Ts...>();
|                                          ~~~~~~~~~~~~~~~~^~

我真的不明白为什么它不工作。每种类型在编译时都是已知的。为什么会发生这种情况,我怎样才能让它工作?我正在使用c++ 11.

在c++模板元编程中,人们称struct元函数是有原因的。

在我们的例子中,在结构体中进行元编程的主要优点是,通过模板参数解决函数重载与类专门化解决函数重载不同,而且更受限制。

所以我建议:

template <class ...> // only called if there's no arguments
struct add_sizes {
static constexpr auto value = 0;
};
template <class T, class ... Ts>
struct add_sizes <T, Ts...> {
static constexpr auto value = T::SIZE + add_sizes<Ts...>::value;
};
// then wrap it into your function:
template <class ... Ts>
constexpr std::size_t totalSize () {
return add_sizes<Ts...>::value;
}

演示

使用结构体的另一个优点是便于"返回";多个值或类型,这对于函数来说很复杂。有时通过计算A你已经计算过B

总的来说,如果你在用函数解决元编程问题时遇到困难,那就改用结构体吧。

问题是当模板参数列表的大小为1时,totalSize<Ts...>();将调用totalSize<>(),但totalSize<>();没有定义。

你可以让你的第一个版本使用2个模板参数。

template<typename T>
constexpr std::size_t totalSize() {
return T::SIZE;
}
template <typename T, typename U, typename... Ts>
constexpr std::size_t totalSize() {
return totalSize<T>() + totalSize<U, Ts...>();
}

演示

相关内容

  • 没有找到相关文章

最新更新