Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to explicitly specialize template to match lambda?

Suppose I have a header wrapper.h:

template <typename Func> void wrapper(const Func func);

and a file wrapper.cpp containing:

#include "wrapper.h"
template <typename Func>
void wrapper(const Func  func)
{
  func();
}

And a file main.cpp containing:

#include "wrapper.h"
#include <iostream>

int main()
{
  wrapper( [](){std::cout<<"hello."<<std::endl;} );
}

If I compile these together (e.g., cat wrapper.cpp main.cpp | g++ -std=c++11 -o main -x c++ -), I get no linker errors.

But if I compile them separately (e.g., g++ -std=c++11 -o wrapper.o -c wrapper.cpp && g++ -std=c++11 -o main main.cpp wrapper.o), I --- of course --- get a linker error:

Undefined symbols for architecture x86_64:
  "void wrapper<main::$_0>(main::$_0)", referenced from:
      _main in main-5f3a90.o

Normally, I could explicitly specialize wrapper and add something like this to wrapper.cpp:

template void wrapper<void(*)()>(void(*)())

But this particular template specialization doesn't work.

Is it possible to specialize a template on a lambda?

like image 508
Alec Jacobson Avatar asked Jun 16 '16 03:06

Alec Jacobson


1 Answers

First, I assume you know about Why can templates only be implemented in the header file?

To your question:

Is it possible to specialize a template on a lambda?

Unfortunately No, template specializations work with exact match, and a lambda is a unique unnamed type. The problem is specializing for that type which you do not know.

Your best bet is to use std::function; or as you have done, then additionally force the lambda to be converted into a function pointer by adding +

int main()
{
  wrapper(+[](){std::cout<<"hello."<<std::endl;} );
}

Full example:

#include <iostream>

template <typename Func>
void wrapper(const Func  func)
{
    std::cout << "PRIMARY\n";
    func();
}

template <>
void wrapper<void(*)()>(void(*func)())
{
    std::cout << "SPECIALIZATION\n";
    func();
}

int main()
{
     wrapper([](){std::cout<<"hello\n"<<std::endl;} );
     wrapper(+[](){std::cout<<"world."<<std::endl;} );
}

This will print

PRIMARY
hello

SPECIALIZATION
world

Also, decltype facility wouldn't help, if it does, it will take away the flexibility of your need for lambda

like image 150
WhiZTiM Avatar answered Nov 11 '22 06:11

WhiZTiM