为什么显式给出的模板参数不能是 "deduced"
why template parameter which is explicitely given can not be "deduced"
来自那个问题:
我尝试实现:
enum Specifier
{
One,
Two,
Three
};
template <Specifier, typename UNUSED=void>
struct Foo
{
void Bar(){ std::cout << "Bar default" << std::endl;}
};
template <Specifier s , typename std::enable_if<s == Specifier::Two || s == Specifier::One, int>::type>
struct Foo<s>
{
void Bar(){ std::cout << "Bar Two" << std::endl; }
};
int main()
{
Foo< One >().Bar();
Foo< Two >().Bar();
}
失败:
> main.cpp:130:8: error: template parameters not deducible in partial specialization:
130 | struct Foo<s>
| ^~~~~~
main.cpp:130:8: note: '<anonymous>'
如何修复那个超级简单的例子?我喜欢 SFINAE :-)
将 enable_if
放入 Foo
的模板参数列表中:
template <Specifier s>
struct Foo<s, typename std::enable_if<s == Specifier::Two || s == Specifier::One, void>::type>
// same as the default type used before ^^^^
demo.
模板特化中的模板参数是不可推导的,这是一个简单的事实。
不是你需要它。
只需更改模板专业化:
template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>
虽然 std::enable_if_t
的结果当然是 int
而不是 void
使它有些无用。
此外,正如其他人评论的那样,使用概念或至少 requires
而不是主模板的额外模板参数要方便得多。
正如错误告诉我们的那样,模板参数在偏特化中是不可推导的。在您的示例中,您已尝试将 SFINAE 构造放置在专业化的模板 parameter 列表中,但您需要将其移动到模板 argument专业化声明的列表(class 被专业化)。
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>
应用于您的示例(稍作清理):
#include <iostream>
#include <type_traits>
enum class Specifier {
One,
Two,
Three
};
template <Specifier, typename = void>
struct Foo {
static void bar() { std::cout << "bar default\n"; }
};
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>> {
static void bar() { std::cout << "bar One or Two\n"; }
};
int main() {
Foo<Specifier::One>::bar(); // bar One or Two
Foo<Specifier::Two>::bar(); // bar One or Two
Foo<Specifier::Three>::bar(); // bar default
}
请注意,您无需在 class 模板的主模板中命名未使用的类型模板参数 Foo
。
来自那个问题:
我尝试实现:
enum Specifier
{
One,
Two,
Three
};
template <Specifier, typename UNUSED=void>
struct Foo
{
void Bar(){ std::cout << "Bar default" << std::endl;}
};
template <Specifier s , typename std::enable_if<s == Specifier::Two || s == Specifier::One, int>::type>
struct Foo<s>
{
void Bar(){ std::cout << "Bar Two" << std::endl; }
};
int main()
{
Foo< One >().Bar();
Foo< Two >().Bar();
}
失败:
> main.cpp:130:8: error: template parameters not deducible in partial specialization:
130 | struct Foo<s>
| ^~~~~~
main.cpp:130:8: note: '<anonymous>'
如何修复那个超级简单的例子?我喜欢 SFINAE :-)
将 enable_if
放入 Foo
的模板参数列表中:
template <Specifier s>
struct Foo<s, typename std::enable_if<s == Specifier::Two || s == Specifier::One, void>::type>
// same as the default type used before ^^^^
demo.
模板特化中的模板参数是不可推导的,这是一个简单的事实。
不是你需要它。
只需更改模板专业化:
template <Specifier s>
struct Foo<s, std::enable_if_t<s == Specifier::Two || s == Specifier::One, int>>
虽然 std::enable_if_t
的结果当然是 int
而不是 void
使它有些无用。
此外,正如其他人评论的那样,使用概念或至少 requires
而不是主模板的额外模板参数要方便得多。
正如错误告诉我们的那样,模板参数在偏特化中是不可推导的。在您的示例中,您已尝试将 SFINAE 构造放置在专业化的模板 parameter 列表中,但您需要将其移动到模板 argument专业化声明的列表(class 被专业化)。
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>>
应用于您的示例(稍作清理):
#include <iostream>
#include <type_traits>
enum class Specifier {
One,
Two,
Three
};
template <Specifier, typename = void>
struct Foo {
static void bar() { std::cout << "bar default\n"; }
};
template <Specifier S>
struct Foo<S, std::enable_if_t<(S == Specifier::Two) || (S == Specifier::One)>> {
static void bar() { std::cout << "bar One or Two\n"; }
};
int main() {
Foo<Specifier::One>::bar(); // bar One or Two
Foo<Specifier::Two>::bar(); // bar One or Two
Foo<Specifier::Three>::bar(); // bar default
}
请注意,您无需在 class 模板的主模板中命名未使用的类型模板参数 Foo
。