验证模板类型的可调用签名
C++ verify callable signature of template type
假设我有一个这样的通用函数:
template<typename TFunc>
void templFunc(TFunc func) {
func(3, 6);
}
在编译时是否有任何方法可以验证TFunc的签名,无论它是std::函数还是lambda或任何类型的函数引用。我只是想确保TFunc是签名void(int, int)或类似于static_assert,所以我可以产生一个非垃圾错误消息。
所以我摆弄了一些type_traits的东西,我想我有一些东西来验证整个签名,而不仅仅是返回值,并允许您创建易于阅读的static_断言,而不是当签名不匹配时难以辨认的模板错误。这是一个糟糕的解决方案吗?
#include <functional>
template<typename, typename, typename = void>
struct is_signature : std::false_type {};
template<typename TFunc, typename Ret, typename... Args>
struct is_signature<TFunc, Ret(Args...),
typename std::enable_if<
std::is_convertible<
TFunc,
std::function<Ret(Args...)>
>::value
>::type
> : public std::true_type
{};
// works on both functions and lambda's
void blah(int, int) {
}
template<typename TFunc>
void templFunc(TFunc func) {
static_assert(is_signature<TFunc, void(int, int)>::value, "Not gonna work! more info follows:");
func(3, 6);
}
int main() {
auto b = [](int, int) -> void {
};
auto c = [](int) -> void {
};
static_assert(is_signature<decltype(b), void(int, int)>::value, "b convertible to a std::function<void(int, int), so this checks out!");
static_assert(is_signature<decltype(b), void(int)>::value, "b not convertible to a std::function<void(int)>, so this will error in compilation.");
static_assert(is_signature<decltype(blah), void(int, int)>::value, "blah convertible to a std::function<void(int, int), so this checks out!");
static_assert(is_signature<decltype(blah), void(int)>::value, "blah not convertible to a std::function<void(int)>, so this will error in compilation.");
templFunc(b); // <- ok
templFunc(c); // <- static assertion : not gonna work!
return 0;
}
您可以使用:
template<typename TFunc>
void templFunc(TFunc func) {
static_assert(std::is_void<decltype(func(0,0))>::value,
"Bad template argument. The return type is not void");
func(3, 6);
}
- 这将确保函数的返回类型为
void
。 如果函数不接受两个参数,它将在调用
func(3,6);
时失败——两次。一次在static_assert
行,一次在下一行如果
int
或int
可以提升、转换或强制转换为的任何其他类型的参数类型,则函数调用将成功。确保参数类型仅为int
将需要一些额外的工作。
测试程序:
#include <type_traits>
template<typename TFunc>
void templFunc(TFunc func) {
static_assert(std::is_void<decltype(func(0,0))>::value, "Bad template argument. The return type is not void");
func(3, 6);
}
void foo()
{
}
void bar(int x, int y)
{
}
int baz(int x, int y)
{
return 0;
}
struct Functor
{
void operator()(long, long)
{
}
};
int main()
{
templFunc(foo); // Not OK. Two few arguments
templFunc(bar); // OK
templFunc(baz); // Not OK. Wrong return type
templFunc([](int, int) -> void {} ); // OK
templFunc(Functor()); // OK
}
类似的东西使用SFINAE工作(仅当您基于模板参数进行断言;我不太确定为什么,我认为这将是最有趣的部分:):)
#include <type_traits>
template<typename TFunc>
typename std::enable_if<std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func)
{
func(3, 6);
}
template<typename TFunc>
typename std::enable_if<!std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value >::type templFunc(TFunc func)
{
static_assert(std::is_same<typename std::result_of<TFunc(int, int)>::type, void>::value, "error; invalid function");
}
auto a = [](int, int) {};
auto b = [](int x, int y) { return x + y; };
int main()
{
templFunc(b);
return 0;
}
相关文章:
- 构造函数正在调用一个使用当前类类型的函数
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 从类型std::函数传递变量失败,尽管调用方期望的类型完全相同
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- C++类型特征,以查看是否可以<uint32_t>对类型"K"的任何变量调用"static_cast(k)"
- 调用外部函数,无法指定类型 C++/MVS
- 如何在另一个类中调用类型类的向量?
- 调用类型的标记构造函数(如果可用),否则为默认值
- C++ 数组和指针调用类型
- 调用类型 'const RadioMap::comp' 的对象没有匹配函数
- 如何调用类型为预定义结构的函数
- 作为模板参数的可调用类型上的C++约束
- 模板类的构造函数在使用 new 关键字时调用类型构造函数
- 在运行时之前调用类型未知的模板化函数
- 在VS2010中获取可调用类型的返回类型
- 在什么情况下会调用类型的转换运算符?
- c++-builder:转换为标准调用类型
- 没有调用类型转换操作符
- C++编译时谓词,用于测试是否可以使用 T 类型的参数调用 F 类型的可调用对象
- 没有匹配函数来调用类型 'hash<char">' 的对象(Stroustrup Book Drill)