即使在编译时已知,也无法推断出模板参数
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++ 模板元编程中调用 struct
s 元函数 是有原因的。
在我们的例子中,在结构中进行元编程的主要优点是通过模板参数解决函数重载与 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;
}
使用结构的另一个优点是可以轻松实现多个值或类型的“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...>();
}
我有一个可变参数模板 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++ 模板元编程中调用 struct
s 元函数 是有原因的。
在我们的例子中,在结构中进行元编程的主要优点是通过模板参数解决函数重载与 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;
}
使用结构的另一个优点是可以轻松实现多个值或类型的“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...>();
}