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

Couldn't deduce template paramter even if it is known at compile time

我有一个可变参数模板 class 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++ 模板元编程中调用 structs 元函数 是有原因的。

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

所以我建议:

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;
}

demo


使用结构的另一个优点是可以轻松实现多个值或类型的“return”,这对于函数来说会变得复杂。有时通过计算 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...>();
}

Demo