Sca*_*nth 9 c++ generic-lambda c++14
可以通过访问它来推断出非泛型lambda的arity operator().
template <typename F>
struct fInfo : fInfo<decltype(&F::operator())> { };
template <typename F, typename Ret, typename... Args>
struct fInfo<Ret(F::*)(Args...)const> { static const int arity = sizeof...(Args); };
Run Code Online (Sandbox Code Playgroud)
对于像没有模板化的东西一样[](int x){ return x; },这很好看operator().
但是,通用lambdas operator()会对模板进行模板化,并且只能访问模板的具体实例 - 这有点问题,因为我无法手动提供模板参数,operator()因为我不知道它是什么.
所以,当然,像
auto lambda = [](auto x){ return x; };
auto arity = fInfo<decltype(lambda)>::arity;
Run Code Online (Sandbox Code Playgroud)
不起作用.
我不知道要投射什么,也不知道提供什么模板参数(或多少)(operator()<??>).
任何想法如何做到这一点?
这种技术在某些情况下会起作用.我创建了一个fake_anything几乎可以伪造任何东西的类型,并尝试用一些实例来调用你的lambda.
#include <iostream>
struct fake_anything {
fake_anything(fake_anything const&);
fake_anything();
fake_anything&operator=(fake_anything const&);
template<class T>operator T&() const;
template<class T>operator T&&() const;
template<class T>operator T const&() const;
template<class T>operator T const&&() const;
fake_anything operator*() const;
fake_anything operator++() const;
fake_anything operator++(int) const;
fake_anything operator->() const;
template<class T>fake_anything(T&&);
};
fake_anything operator+(fake_anything, fake_anything);
fake_anything operator-(fake_anything, fake_anything);
fake_anything operator*(fake_anything, fake_anything);
fake_anything operator/(fake_anything, fake_anything);
// etc for every operator
template<class>using void_t=void;
template<class Sig, class=void>
struct can_invoke:std::false_type{};
template<class F, class...Args>
struct can_invoke<F(Args...),
void_t< decltype( std::declval<F>()( std::declval<Args>()... ) ) >
> : std::true_type
{};
template<class Sig>struct is_sig:std::false_type{};
template<class R, class...Args>struct is_sig<R(Args...)>:std::true_type{};
template<unsigned...>struct indexes{using type=indexes;};
template<unsigned Max,unsigned...Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned max>using make_indexes_t=typename make_indexes<max>::type;
template<class T,unsigned>using unpacker=T;
template<class F, class A, class indexes>
struct nary_help;
template<class F, class A, unsigned...Is>
struct nary_help<F,A,indexes<Is...>>:
can_invoke<F( unpacker<A,Is>... )>
{};
template<class F, unsigned N>
struct has_n_arity:
nary_help<F, fake_anything, make_indexes_t<N>>
{};
template<class F, unsigned Min=0, unsigned Max=10>
struct max_arity{
enum{Mid=(Max+Min)/2};
enum{
lhs = max_arity<F,Min,Mid>::value,
rhs = max_arity<F,Mid+1,Max>::value,
value = lhs>rhs?lhs:rhs,
};
};
template<class F, unsigned X>
struct max_arity<F,X,X>:
std::integral_constant<int, has_n_arity<F,X>::value?(int)X:-1>
{};
template<class F, unsigned Min=0, unsigned Max=10>
struct min_arity{
enum{Mid=(Max+Min)/2};
enum{
lhs = min_arity<F,Min,Mid>::value,
rhs = min_arity<F,Mid+1,Max>::value,
value = lhs<rhs?lhs:rhs,
};
};
template<class F, unsigned X>
struct min_arity<F,X,X>:
std::integral_constant<unsigned,has_n_arity<F,X>::value?X:(unsigned)-1>
{};
auto test1 = [](auto x, auto y)->bool { return x < y; };
auto test2 = [](auto x, auto y) { return x + y; };
auto test3 = [](auto x) { return x.y; };
int main() {
std::cout << can_invoke< decltype(test1)( fake_anything, fake_anything ) >::value << "\n";
std::cout << can_invoke< decltype(test1)( int, int ) >::value << "\n";
std::cout << has_n_arity< decltype(test1), 2 >::value << "\n";
std::cout << max_arity< decltype(test1) >::value << "\n";
std::cout << max_arity< decltype(test2) >::value << "\n";
// will fail to compile:
// std::cout << max_arity< decltype(test3) >::value << "\n";
}
Run Code Online (Sandbox Code Playgroud)
实例.
注意,足够的SFINAE将意味着上述将得到错误的结果,将使用operator.或使用operator.某些类型的"派生"类型,或根据fake_anything参数访问类型等.
但是,如果lambda使用->X子句指定其返回值,那么fake_anything就足够了.困难的部分是处理身体.
请注意,这种方法通常是一个坏主意,因为如果您想知道函数的arity,您可能也知道要调用函数对象的事物的类型!上面我很容易回答这个问题(可以用这些参数调用这个函数对象吗?).甚至可以改进来询问"这些参数的最长/最短前缀是什么,可以调用这个函数对象",或者处理"有多少次类型X重复调用这个函数对象"(如果你想干净失败,你需要一个上限).
这是不可能的,因为函数调用运算符可以是可变参数模板。对于一般的函数对象来说,永远这样做是不可能的,而特殊情况下的 lambda 表达式(因为它们碰巧不是同样强大)总是一个坏主意。现在正是这个坏主意得到报应的时候了。
| 归档时间: |
|
| 查看次数: |
937 次 |
| 最近记录: |