检测是否存在具有给定签名的函数
Detect if function with given signature exists
我正在尝试使用模板元编程来查找具有特定签名的函数(不是 class 方法)。为了实现这一点,我想使用 detection idiom.
假设我有函数 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
我尝试按照 link 接受的答案中的步骤进行操作,但是当我尝试将 float
传递给期望 int
.
的函数
此外,如果我可以将任何函数传递给 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{};
}
并变得更加灵活(因为也可以接受 const
and/or 引用类型 Ts...
)。
下面是一个完整的编译示例
#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 );
}
我正在尝试使用模板元编程来查找具有特定签名的函数(不是 class 方法)。为了实现这一点,我想使用 detection idiom.
假设我有函数 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
.
此外,如果我可以将任何函数传递给 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{};
}
并变得更加灵活(因为也可以接受 const
and/or 引用类型 Ts...
)。
下面是一个完整的编译示例
#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 );
}