我想编写一个模板函数,只能使用2个数字(例如3和5),如果你尝试将它与其他数字一起使用,则会给出错误。
我可以这样做:
template<int x>
void f();
template<>
void f<3>()
{
cout << "f<3>()\n";
}
template<>
void f<5>()
{
cout << "f<5>()\n";
}
然后我可以正常方式调用此函数:
f<3>();
f<5>();
它编译得很好,如果我尝试错误地使用我的函数:
f<10>();
编译器给我一个错误。
这种方法有两个问题:
1.-这是标准吗?我可以使用整数专门设计模板吗?
2.-我不喜欢你使用这种方法时得到的错误,因为错误并没有告诉用户他做错了什么。我更喜欢写类似的东西:
template<int x>
void f()
{
static_assert(false, "You are trying to use f with the wrong numbers");
}
但这并没有编译。看来我的编译器(gcc 5.4.0)试图首先实例化主模板,因此它会给出错误(static_assert)。
感谢您的帮助。
如果您想知道我为什么要这样做,那是因为我正在学习如何编程微控制器。在微控制器中,你有一些只做一些事情的引脚。例如,引脚3和5是可以生成方波的引脚。如果在一个应用程序中我想生成一个方波,我想写下这样的东西:
square_wave<3>(frecuency);
但是,如果几个月后我想在另一个应用程序中使用不同的微控制器重用这个代码(或更改它),我希望我的编译器对我说:&#34;呃,在这个微控制器中你可以&#39; t在引脚3和5中产生方波。相反,使用引脚7和9&#34;。我认为这可以为我节省很多麻烦(或许不是,我真的不知道。我只是学习如何编程微控制器)。
答案 0 :(得分:5)
1.-这是标准吗?我可以使用整数专门设计模板吗?
是
2
template<int x>
void f()
{
static_assert(false, "You are trying to use f with the wrong numbers");
}
您需要将静态断言条件更改为依赖于模板参数值的内容。像
这样简单的东西template <int x>
void f()
{
static_assert(x - x, "You are trying to use f with the wrong numbers");
}
应该有用。
顺便说一下,值得注意的是,通常认为专门化功能模板并不是一个好主意,因为专业化与功能重载的交互很糟糕(或者至少有些不可预测)。因此,通常使用函数对象可能是更好的主意:
template <int I>
struct do_f {
static_assert(I - I, "You are trying to use f with the wrong numbers");
};
template <>
struct do_f<3> {
void operator()(args...) { ... }
};
template <>
struct do_f<5> {
void operator()(args...) { ... }
};
然后你可以编写一个调用函数对象的包装函数:
template <int I>
void f(args...) {
do_f<I>{}(args...);
}
答案 1 :(得分:2)
static_assert
的条件始终为false
,这使得在选择规范之前,无法在重载决策中选择主模板。您可以根据tempalate参数static_assert
更改x
的条件。 .e.g
template<int x>
void f()
{
static_assert(x == 3 || x == 5, "You are trying to use f with the wrong numbers");
}
从标准$17.7/8,9 Name resolution [temp.res]:
开始由于不依赖于模板参数的构造,在其定义之后立即对模板进行假设实例化将是不正确的
...
否则,不能为可以生成有效特化的模板发出诊断。
和$17.7.2/1 Dependent names [temp.dep]:
在模板内部,一些构造的语义可能因实例而异。这样的构造取决于模板参数。
答案 2 :(得分:0)
其他答案仅提出解决方法。特别是因为它涉及编写一些样板代码。最简单的事情是
template<int x>
void f() = delete;
然后您将获得一个很好的编译器错误,如
error: call to deleted function 'f'
当您尝试为非专业化int
实例化模板时。
#include <iostream>
template<int x>
void f() = delete;
template<>
void f<3>()
{
std::cout << "f<3>()\n";
}
template<>
void f<5>()
{
std::cout << "f<5>()\n";
}
int main()
{
f<3>();
f<5>();
f<10>(); // BOOM!
}