Home > Enterprise >  template deduction guide fails with lambda but not global function
template deduction guide fails with lambda but not global function

Time:01-12

I have a simple class which stores a callable (either a lambda or global function) and a void*, both of which are passed on construction:

#include <iostream>
#include <vector>
#include <functional>

using namespace std;

template <typename>
class LyricAnatali;

template <typename Res, typename... Args>
class LyricAnatali<Res(Args...)> {
public:
  template <typename F>
  LyricAnatali(F&& f, void* data)
    : m_ptr(f), m_userData(data) {}

private:
  Res(*m_ptr)(void*, Args...) = nullptr;
  void* m_userData;
};

// Deduction guide
template <typename Res, typename... Args>
LyricAnatali(Res(*)(void*, Args...), void*) -> LyricAnatali<Res(Args...)>;

int GlobalFunction(void*, const string& s, const vector<int>& t, int u) { return 0; }

int main() {
  auto lg = [](void*, const string& s, const vector<int>& t, int u) -> int { return 0; };

  LyricAnatali<int(const string& s, const vector<int>& t, int u)> func(lg, 0);  // Compiles

  auto lambda = LyricAnatali(lg, 0); // Does not compile

  auto global = LyricAnatali(GlobalFunction, 0); // Compiles
  auto stdFunc = std::function(lg); // Compiles
}

The line indicated above does not compile. From https://godbolt.org/z/7K3K48Tn4, I feel the relevant error is:

could not match 'Res (*)(void *, Args...)' against '(lambda at <source>:28:13)'
LyricAnatali(Res(*)(void*, Args...), void*) -> LyricAnatali<Res(Args...)>;

I don't understand enough about deduction guides to know how to fix this. Can someone please advise how I can get this to work when passing a lambda?

CodePudding user response:

lambda is a class type with operator() (const in this case), and would not match a function pointer, you'd need to write deduction guide for that. (this is general template deduction rule, not limit to CTAD)


a possible implementation

template <typename...>
struct parse_member{};

template <typename R, typename G, typename... A>
struct parse_member<R(G::*)(void*, A...)const>{ // and all combination of const, noexcept, volatile, &, &&, for general case 
    using type = R(A...);
};

template <
   typename F, 
   typename sig = typename parse_member<decltype(&F::operator())>::type
>
LyricAnatali(F, void*) -> LyricAnatali<sig>;

https://godbolt.org/z/sTsovGEvd

  • Related