检测是否存在具有给定签名的函数
Detect if function with given signature exists
我正在尝试使用模板元编程来查找具有特定签名的函数(不是类方法(。为了实现这一点,我想使用检测习惯用语。
假设我有foo()
和bar()
的函数:
void foo(int x);
template<typename... Ts>
void bar(Ts&& ...args);
另一个称为foobar()
的函数接收一个函数和一个参数包。foobar()
检查是否可以使用通过参数包接收的参数调用接收的函数:
template<typename F, typename... Ts>
void foobar(F&& fun, Ts&& ...args) {
if constexpr(func_with_signature_exists_v<fun(declval<Args>()...)>)
do_something;
}
我希望foobar()
if
声明得出以下结果:
if constexpr(func_with_signature_exists_v<foo(int)>) // true
if constexpr(func_with_signature_exists_v<foo(float)>) // false
if constexpr(func_with_signature_exists_v<foo(int, int)>) // false
if constexpr(func_with_signature_exists_v<bar(int)>) // true
if constexpr(func_with_signature_exists_v<bar(int, int)>) // true
if constexpr(func_with_signature_exists_v<bar(int, float, int)>) // true
我尝试按照此链接中接受的答案中的步骤进行操作,但是当我尝试将float
传递给期望int
的函数时,is_detected习语并没有抱怨。
另外,我宁愿我可以将任何函数传递给 using 语句,而不是明确地将其专门用于一个特定函数,如下所示:
template<typename... Args>
using test_t = decltype(f(std::declval<Args>()...));
有什么方法可以实现我想要的吗?还是类似的东西?
请注意,这是针对一个副项目,所以我尝试使用 C++17,而不是 C++14 或 C++11。
foo()
和bar()
给出了完全不同的问题。
首先:bar()
,这是一个模板函数。
鉴于您希望bar()
是一个模板函数(如果是一个class
/struct
的模板operator()
则不同(,如果您想要一些东西
static_assert(foobar(bar, 1));
我能想象到的最好的情况是,foobar()
应该使用C风格的宏;而可变参数宏,以使事情变得更加复杂(但不要要求我开发该宏(。
这是因为不能将模板函数作为函数参数传递,因为模板函数不是对象,而是一组对象。
对于foo()
,如果我理解正确,问题是当参数可转换为函数参数时,检测习惯用语说真
static_assert(foobar(foo, 3.4)); // you get true but you want false
并且您希望将函数作为参数传递。
这很容易解决(但我认为不是很有用(。
如果您声明(无需定义(几个重载函数,如下所示
template <typename ... Args, typename R>
std::true_type fwse (R(*)(Args...), int);
template <typename ..., typename T>
std::false_type fwse (T, long);
和一个constexpr
可变参数模板变量
template <typename T, typename ... Args>
constexpr auto func_with_signature_exists_v
= decltype(fwse<Args...>(std::declval<T>(), 0))::value;
您也可以按如下方式编写foobar()
template <typename F, typename ... Ts>
constexpr auto foobar (F, Ts const & ...)
{
if constexpr ( func_with_signature_exists_v<F, Ts...> )
return std::true_type{};
else
return std::false_type{};
}
你得到
static_assert( foobar(foo, 7) == true );
static_assert( foobar(foo, 3.4) == false );
static_assert( foobar(foo, 1, 2) == false );
我认为这不是很有用,因为当foo()
参数的类型必须是纯类型(没有const
,没有引用(时,这有效。
如果可以避免将值传递给foobar()
,并且如果可以直接传递Args...
类型
static_assert( foobar<int>(foo) == true );
static_assert( foobar<double>(foo) == false );
static_assert( foobar<int, int>(foo) == false );
您可以按如下方式重写foobar()
template <typename ... Ts, typename F>
constexpr auto foobar (F)
{
if constexpr ( func_with_signature_exists_v<F, Ts...> )
return std::true_type{};
else
return std::false_type{};
}
并变得更加灵活(因为也可以接受Ts...
的const
和/或引用类型(。
以下是完整的编译示例
#include <type_traits>
void foo(int x)
{ }
template <typename ... Args, typename R>
std::true_type fwse (R(*)(Args...), int);
template <typename ..., typename T>
std::false_type fwse (T, long);
template <typename T, typename ... Args>
constexpr auto func_with_signature_exists_v
= decltype(fwse<Args...>(std::declval<T>(), 0))::value;
template <typename ... Ts, typename F>
constexpr auto foobar (F)
{
if constexpr ( func_with_signature_exists_v<F, Ts...> )
return std::true_type{};
else
return std::false_type{};
}
int main ()
{
static_assert( foobar<int>(foo) == true );
static_assert( foobar<double>(foo) == false );
static_assert( foobar<int, int>(foo) == false );
}
- 函数是否可以访问传递给main()的参数
- 根据某个函数是否存在启用模板
- 无论如何,我可以确定构造函数是否存在吗?
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 如何检查函数是否在LLVM Instrumentation pass的ModulePass的系统头文件中定义?
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- 在对象构造期间,将指向尚未构造的子对象的指针传递给另一个子对象的构造函数是否危险?
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- 调用 erase() 函数是否也会在擦除元素之前更改迭代器值?
- 由并发无序映射查找线程调用的函数是否安全?
- 使用静态成员函数而不是普通函数是否有任何开销?
- 从其存储的回调中删除 std::函数是否安全
- 析构函数是否会自动调用 delete[] C++?
- 构造函数是否有一种现代C++方法来了解其'container'类?
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- 移动构造函数是否C++过时?
- 在 c++ 中将对象设置为等于同一类的构造函数是否有效?
- 此函数是否会在C++中创建内存泄漏?
- 具有默认值的单个参数构造函数是否与默认构造函数相同?
- 如何检测构造函数是否与抛出的析构函数无关