How to invoke c_str() for std::string variadic template parameters? - c++

I have a method that accepts format string + arguments (right as printf()), however, I'm using variadic templates for this purpose:
template<typename... Args>
static void log(const char* pszFmt, Args&&... args)
{
doSomething(pszFmt, std::forward<Args>(args)...);
}
Some of args can be std::string instances. Is it possible to make sure that doSomething will never accept std::string, but will always accept const char* instead of each source std::string passed to log()?
In other words, I need a way to forward all the args to doSomething() making all the std::string arguments substituted with what std::string::c_str() returns.
Thanks in advance!

You could define your own "forwarding" method:
template<typename T>
decltype(auto) myForward(T&& t)
{
return t;
}
template<>
decltype(auto) myForward(std::string& t)
{
return t.c_str();
}
template<>
decltype(auto) myForward(std::string&& t)
{
return t.c_str();
}
template<typename... Args>
static void log(const char* pszFmt, Args&&... args)
{
doSomething(pszFmt, myForward<Args>(std::forward<Args>(args))...);
}

C++17 version
You can use SFINAE to achieve this:
#include <iostream>
#include <utility>
#include <string>
template <typename, typename = void>
struct has_c_str : std::false_type {};
template <typename T>
struct has_c_str<T, std::void_t<decltype(&T::c_str)>> : std::is_same<char const*, decltype(std::declval<T>().c_str())>
{};
template <typename StringType,
typename std::enable_if<has_c_str<StringType>::value, StringType>::type* = nullptr>
static void log(const char* pszFmt, StringType const& arg) {
std::cout << "std::string version" << std::endl;
}
template <typename StringType,
typename std::enable_if<!has_c_str<StringType>::value, StringType>::type* = nullptr>
static void log(const char* pszFmt, StringType arg) {
std::cout << "const char * version" << std::endl;
}
template <typename... Args>
static void log(const char* pszFmt, Args&&... args) {
log(pszFmt, std::forward<Args>(args)...);
}
int main() {
log("str", std::string("aa")); // output: std::string version
log("str", "aa"); // output: const char * version
return 0;
}
Full demo here

Here's an alternative solution. If your logger simply prints each argument and doesn't "store" it, then there's no need to perfect-forward the arguments, a simple pass-by-reference will suffice.
In that case you can simply overload or specialize the printer function for various "printable" types.
template <class T>
decltype(auto) printer(T const& t) {
return t;
}
inline const char* printer(std::string const& t) {
return t.c_str();
}
template<typename... Args>
void log(const char* pszFmt, Args const&... args) {
printf(pszFmt, printer(args)...);
}
int main() {
std::string str{"xyz"};
log("%s %s %s\n", "abc", std::string("def"), str);
}
Note: the non-template overload will always be preferred during overload resolution.

Related

Deducing variadic template depending on argument count

Imagine I have two functions:
void string(const char *str)
{
std::cout << "this is string" << std::endl;
}
void number(const char *str, double f)
{
std::cout << "this is number" << std::endl;
}
I want to write a generic wrapper so that be able to call format() like this:
int main() {
format("single arg");
format("format string", 1.0);
format("single arg", "format string", 1.0);
format("format string 1", 1.0, "just string arg", "format string 2", 2.0);
return 0;
}
That is if arguments come in pair {string, number}, then invoke number(); otherwise call string(). Obviously, it can be done only unpacking arguments right-to-left. I've tried to implement it following (wrong) way:
template<class T>
void operation(T first)
{
string(first);
}
template<class T, class U = float>
void operation(T first, U second)
{
number(first, second);
}
template<class ... ARGS>
void format(ARGS ... args)
{
auto last = (args, ...);
using last_type = typename decltype(last);
if constexpr (std::is_arithmetic_v<last_type>)
(..., operation(args, last));
else
(..., operation(args));
}
The problem is that while unpacking operation(args, last) we will get both args and last floats. I believe there's some easy way to achieve what I want (without relying on tuples etc).
Here is a proof-of-concept using only overload resolution. I'm not sure how scalable it is, though.
void format() {}
void format(char const *str) {
string(str);
}
template <class... Args>
void format(char const *str, char const *nextStr, Args... args);
template <class... Args>
void format(char const *str, double f, Args... args);
template <class... Args>
void format(char const *str, char const *nextStr, Args... args) {
string(str);
format(nextStr, args...);
}
template <class... Args>
void format(char const *str, double f, Args... args) {
number(str, f);
format(args...);
}
See it live on Godbolt.org

confusion about universal reference. In my code f(T&&...) compiler error but f(T...) succeed

My workspace is in Windows, Visual Studio 2017. I write two templates to change all str-like to std::wstring. But a complier err comes:
Error C2975
'_Test': invalid template argument for 'std::conditional', expected compile-time constant expression
My code is following:
#include <codecvt>
#include <iostream>
std::wstring to_wide_string(const std::string& input)
{
std::wstring_convert<std::codecvt_utf8<wchar_t> > converter;
return converter.from_bytes(input);
}
std::string to_byte_string(const std::wstring& input)
{
std::wstring_convert<std::codecvt_utf8<wchar_t> > converter;
return converter.to_bytes(input);
}
// a template to check if the Args can be used in F's constructors.
// for example , check<std::string>(3, 'a').value == true
template <class F>
struct check
{
template <class... Args>
constexpr check(Args&&... args) : value(
std::is_void<
decltype(t2<F, Args...>(0, std::forward<Args>(args)...))
>::type::value) {}
bool value;
struct nat {};
template <class G, class... GArgs>
static auto t2(int, GArgs&&... args) -> decltype(G(std::forward<GArgs>(args)...), void());
template <class, class...>
static auto t2(...)->nat;
};
// this template is make all wstr-like to std::string. But I don't finish it yet
template <typename T, bool is_wstring = std::is_same<std::wstring, std::decay_t<T>>::value>
struct to_tstring : std::string
{
};
// I want all str-like can be translated to std::wstring
template <typename T>
struct to_tstring<T, true> : std::wstring
{
template <typename... Args>
// if I change Args&&... to Args..., it will compile succeed
to_tstring(Args&&... args) : to_tstring<T, true>(
std::conditional<
check<std::string>(std::forward<Args>(args)...).value,
std::true_type, std::false_type
>::type(),
std::forward<Args>(args)...
)
{
std::cout << "to_tstring<T, true>::ctor_1" << std::endl;
}
private:
template <typename... Args>
to_tstring(std::false_type, Args&&... args) : std::wstring(std::forward<Args>(args)...) {
std::cout << "to_tstring<T, true>::ctor_2 false_type" << std::endl;
}
template <typename... Args>
to_tstring(std::true_type, Args&&... args) : std::wstring(to_wide_string(std::string(std::forward<Args>(args)...))) {
std::cout << "to_tstring<T, true>::ctor_3 true_type" << std::endl;
}
};
int main()
{
to_tstring<std::wstring> a("asdf"); // compiler error
return 0;
}
I don't know why the std::conditional does not recognize the checkstd::string(std::forward(args)...).value. It's fine to be a constexpr when I used it in main:
int main()
{
constexpr int i = check<std::string>(3,'j').value;
int s[i] = {}; // it's fine
}
By coincidence, I change the signature from to_tstring(Args&&... args) to to_tstring(Args... args), now it is successful to complie. But I don't know why.
The reason I need those template, it's I have a macro called TSTRING. TSTIRNG is std::string in WIN32, std::wstring in x64. Sometimes std::string and std::wstring can be showed at same time, so I want to tranform all the string I meeted to TSTRING

CTAD for templated function [duplicate]

The C++20 feature std::source_location is used to capture information about the context in which a function is called.
When I try to use it with a variadic template function, I encountered a problem: I can't see a place to put the source_location parameter.
The following doesn't work because variadic parameters have to be at the end:
// doesn't work
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
The following doesn't work either because the caller will be screwed up by the parameter inserted in between:
// doesn't work either, because ...
template <typename... Args>
void debug(const std::source_location& loc = std::source_location::current(),
Args&&... args);
// the caller will get confused
debug(42); // error: cannot convert 42 to std::source_location
I was informed in a comment that std::source_location works seamlessly with variadic templates, but I struggle to figure out how. How can I use std::source_location with variadic template functions?
The first form can be made to work, by adding a deduction guide:
template <typename... Ts>
struct debug
{
debug(Ts&&... ts, const std::source_location& loc = std::source_location::current());
};
template <typename... Ts>
debug(Ts&&...) -> debug<Ts...>;
Test:
int main()
{
debug(5, 'A', 3.14f, "foo");
}
DEMO
If your function has a fixed parameter before the variadiac arguments, like a printf format string, you could wrap that parameter in a struct that captures source_location in its constructor:
struct FormatWithLocation {
const char* value;
std::source_location loc;
FormatWithLocation(const char* s,
const std::source_location& l = std::source_location::current())
: value(s), loc(l) {}
};
template <typename... Args>
void debug(FormatWithLocation fmt, Args&&... args) {
printf("%s:%d] ", fmt.loc.file_name(), fmt.loc.line());
printf(fmt.value, args...);
}
int main() { debug("hello %s\n", "world"); }
Just put your arguments in a tuple, no macro needed.
#include <source_location>
#include <tuple>
template <typename... Args>
void debug(
std::tuple<Args...> args,
const std::source_location& loc = std::source_location::current())
{
std::cout
<< "debug() called from source location "
<< loc.file_name() << ":" << loc.line() << '\n';
}
And this works*.
Technically you could just write:
template <typename T>
void debug(
T arg,
const std::source_location& loc = std::source_location::current())
{
std::cout
<< "debug() called from source location "
<< loc.file_name() << ":" << loc.line() << '\n';
}
but then you'd probably have to jump through some hoops to get the argument types.
* In the linked-to example, I'm using <experimental/source_location> because that's what compilers accept right now. Also, I added some code for printing the argument tuple.
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
"works", but requires to specify template arguments as there are non deducible as there are not last:
debug<int>(42);
Demo
Possible (not perfect) alternatives include:
use overloads with hard coded limit (old possible way to "handle" variadic):
// 0 arguments
void debug(const std::source_location& loc = std::source_location::current());
// 1 argument
template <typename T0>
void debug(T0&& t0,
const std::source_location& loc = std::source_location::current());
// 2 arguments
template <typename T0, typename T1>
void debug(T0&& t0, T1&& t1,
const std::source_location& loc = std::source_location::current());
// ...
Demo
to put source_location at first position, without default:
template <typename... Args>
void debug(const std::source_location& loc, Args&&... args);
and
debug(std::source_location::current(), 42);
Demo
similarly to overloads, but just use tuple as group
template <typename Tuple>
void debug(Tuple&& t,
const std::source_location& loc = std::source_location::current());
or
template <typename ... Ts>
void debug(const std::tuple<Ts...>& t,
const std::source_location& loc = std::source_location::current());
with usage
debug(std::make_tuple(42));
Demo
Not a great solution but... what about place the variadic arguments in a std::tuple?
I mean... something as
template <typename... Args>
void debug (std::tuple<Args...> && t_args,
std::source_location const & loc = std::source_location::current());
Unfortunately, this way you have to explicitly call std::make_tuple calling it
debug(std::make_tuple(1, 2l, 3ll));
You can try make it:
#include <iostream>
#include <experimental/source_location>
struct log
{
log(std::experimental::source_location location = std::experimental::source_location::current()) : location { location } {}
template<typename... Args>
void operator() (Args... args)
{
std::cout << location.function_name() << std::endl;
std::cout << location.line() << std::endl;
}
std::experimental::source_location location;
};
int main()
{
log()("asdf");
log()(1);
}
DEMO
If you can accept the use of macros, you can write this to avoid explicitly passing in std::source_ location::current():
template <typename... Args>
void debug(const std::source_location& loc, Args&&... args);
#define debug(...) debug(std::source_location::current() __VA_OPT__(,) __VA_ARGS__)

How to use source_location in a variadic template function?

The C++20 feature std::source_location is used to capture information about the context in which a function is called.
When I try to use it with a variadic template function, I encountered a problem: I can't see a place to put the source_location parameter.
The following doesn't work because variadic parameters have to be at the end:
// doesn't work
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
The following doesn't work either because the caller will be screwed up by the parameter inserted in between:
// doesn't work either, because ...
template <typename... Args>
void debug(const std::source_location& loc = std::source_location::current(),
Args&&... args);
// the caller will get confused
debug(42); // error: cannot convert 42 to std::source_location
I was informed in a comment that std::source_location works seamlessly with variadic templates, but I struggle to figure out how. How can I use std::source_location with variadic template functions?
The first form can be made to work, by adding a deduction guide:
template <typename... Ts>
struct debug
{
debug(Ts&&... ts, const std::source_location& loc = std::source_location::current());
};
template <typename... Ts>
debug(Ts&&...) -> debug<Ts...>;
Test:
int main()
{
debug(5, 'A', 3.14f, "foo");
}
DEMO
If your function has a fixed parameter before the variadiac arguments, like a printf format string, you could wrap that parameter in a struct that captures source_location in its constructor:
struct FormatWithLocation {
const char* value;
std::source_location loc;
FormatWithLocation(const char* s,
const std::source_location& l = std::source_location::current())
: value(s), loc(l) {}
};
template <typename... Args>
void debug(FormatWithLocation fmt, Args&&... args) {
printf("%s:%d] ", fmt.loc.file_name(), fmt.loc.line());
printf(fmt.value, args...);
}
int main() { debug("hello %s\n", "world"); }
Just put your arguments in a tuple, no macro needed.
#include <source_location>
#include <tuple>
template <typename... Args>
void debug(
std::tuple<Args...> args,
const std::source_location& loc = std::source_location::current())
{
std::cout
<< "debug() called from source location "
<< loc.file_name() << ":" << loc.line() << '\n';
}
And this works*.
Technically you could just write:
template <typename T>
void debug(
T arg,
const std::source_location& loc = std::source_location::current())
{
std::cout
<< "debug() called from source location "
<< loc.file_name() << ":" << loc.line() << '\n';
}
but then you'd probably have to jump through some hoops to get the argument types.
* In the linked-to example, I'm using <experimental/source_location> because that's what compilers accept right now. Also, I added some code for printing the argument tuple.
template <typename... Args>
void debug(Args&&... args,
const std::source_location& loc = std::source_location::current());
"works", but requires to specify template arguments as there are non deducible as there are not last:
debug<int>(42);
Demo
Possible (not perfect) alternatives include:
use overloads with hard coded limit (old possible way to "handle" variadic):
// 0 arguments
void debug(const std::source_location& loc = std::source_location::current());
// 1 argument
template <typename T0>
void debug(T0&& t0,
const std::source_location& loc = std::source_location::current());
// 2 arguments
template <typename T0, typename T1>
void debug(T0&& t0, T1&& t1,
const std::source_location& loc = std::source_location::current());
// ...
Demo
to put source_location at first position, without default:
template <typename... Args>
void debug(const std::source_location& loc, Args&&... args);
and
debug(std::source_location::current(), 42);
Demo
similarly to overloads, but just use tuple as group
template <typename Tuple>
void debug(Tuple&& t,
const std::source_location& loc = std::source_location::current());
or
template <typename ... Ts>
void debug(const std::tuple<Ts...>& t,
const std::source_location& loc = std::source_location::current());
with usage
debug(std::make_tuple(42));
Demo
Not a great solution but... what about place the variadic arguments in a std::tuple?
I mean... something as
template <typename... Args>
void debug (std::tuple<Args...> && t_args,
std::source_location const & loc = std::source_location::current());
Unfortunately, this way you have to explicitly call std::make_tuple calling it
debug(std::make_tuple(1, 2l, 3ll));
You can try make it:
#include <iostream>
#include <experimental/source_location>
struct log
{
log(std::experimental::source_location location = std::experimental::source_location::current()) : location { location } {}
template<typename... Args>
void operator() (Args... args)
{
std::cout << location.function_name() << std::endl;
std::cout << location.line() << std::endl;
}
std::experimental::source_location location;
};
int main()
{
log()("asdf");
log()(1);
}
DEMO
If you can accept the use of macros, you can write this to avoid explicitly passing in std::source_ location::current():
template <typename... Args>
void debug(const std::source_location& loc, Args&&... args);
#define debug(...) debug(std::source_location::current() __VA_OPT__(,) __VA_ARGS__)

What is a good way to register functions for dynamic invocation in C++?

In my current setup, I have a
typedef std::function<void (MyClass&, std::vector<std::string>) MyFunction;
std::map<std::string, MyFunction> dispatch_map;
And I register my functions in it with a macro. However, I have a problem with this: the parameters are passed as a vector of strings, which I have to convert inside the functions. I would rather do this conversion outside the functions, at the dispatcher level. Is this possible? The function signatures are known at compile time, and never change at run time.
You can get pretty far with variadic templates and some template/virtual techniques. With the following codes, you'll be able to do something like:
std::string select_string (bool cond, std::string a, std::string b) {
return cond ? a : b;
}
int main () {
Registry reg;
reg.set ("select_it", select_string);
reg.invoke ("select_it", "1 John Wayne"));
reg.invoke ("select_it", "0 John Wayne"));
}
output:
John
Wayne
Full implementation:
These codes are exemplary. You should optimize it to provide perfect forwarding less redundancy in parameter list expansion.
Headers and a test-function
#include <functional>
#include <string>
#include <sstream>
#include <istream>
#include <iostream>
#include <tuple>
std::string select_string (bool cond, std::string a, std::string b) {
return cond ? a : b;
}
This helps us parsing a string and putting results into a tuple:
//----------------------------------------------------------------------------------
template <typename Tuple, int Curr, int Max> struct init_args_helper;
template <typename Tuple, int Max>
struct init_args_helper<Tuple, Max, Max> {
void operator() (Tuple &, std::istream &) {}
};
template <typename Tuple, int Curr, int Max>
struct init_args_helper {
void operator() (Tuple &tup, std::istream &is) {
is >> std::get<Curr>(tup);
return init_args_helper<Tuple, Curr+1, Max>() (tup, is);
}
};
template <int Max, typename Tuple>
void init_args (Tuple &tup, std::istream &ss)
{
init_args_helper<Tuple, 0, Max>() (tup, ss);
}
This unfolds a function pointer and a tuple into a function call (by function-pointer):
//----------------------------------------------------------------------------------
template <int ParamIndex, int Max, typename Ret, typename ...Args>
struct unfold_helper;
template <int Max, typename Ret, typename ...Args>
struct unfold_helper<Max, Max, Ret, Args...> {
template <typename Tuple, typename ...Params>
Ret unfold (Ret (*fun) (Args...), Tuple tup, Params ...params)
{
return fun (params...);
}
};
template <int ParamIndex, int Max, typename Ret, typename ...Args>
struct unfold_helper {
template <typename Tuple, typename ...Params>
Ret unfold (Ret (*fun) (Args...), Tuple tup, Params ...params)
{
return unfold_helper<ParamIndex+1, Max, Ret, Args...> ().
unfold(fun, tup, params..., std::get<ParamIndex>(tup));
}
};
template <typename Ret, typename ...Args>
Ret unfold (Ret (*fun) (Args...), std::tuple<Args...> tup) {
return unfold_helper<0, sizeof...(Args), Ret, Args...> ().unfold(fun, tup);
}
This function puts it together:
//----------------------------------------------------------------------------------
template <typename Ret, typename ...Args>
Ret foo (Ret (*fun) (Args...), std::string mayhem) {
// Use a stringstream for trivial parsing.
std::istringstream ss;
ss.str (mayhem);
// Use a tuple to store our parameters somewhere.
// We could later get some more performance by combining the parsing
// and the calling.
std::tuple<Args...> params;
init_args<sizeof...(Args)> (params, ss);
// This demondstrates expanding the tuple to full parameter lists.
return unfold<Ret> (fun, params);
}
Here's our test:
int main () {
std::cout << foo (select_string, "0 John Wayne") << '\n';
std::cout << foo (select_string, "1 John Wayne") << '\n';
}
Warning: Code needs more verification upon parsing and should use std::function<> instead of naked function pointer
Based on above code, it is simple to write a function-registry:
class FunMeta {
public:
virtual ~FunMeta () {}
virtual boost::any call (std::string args) const = 0;
};
template <typename Ret, typename ...Args>
class ConcreteFunMeta : public FunMeta {
public:
ConcreteFunMeta (Ret (*fun) (Args...)) : fun(fun) {}
boost::any call (std::string args) const {
// Use a stringstream for trivial parsing.
std::istringstream ss;
ss.str (args);
// Use a tuple to store our parameters somewhere.
// We could later get some more performance by combining the parsing
// and the calling.
std::tuple<Args...> params;
init_args<sizeof...(Args)> (params, ss);
// This demondstrates expanding the tuple to full parameter lists.
return unfold<Ret> (fun, params);
}
private:
Ret (*fun) (Args...);
};
class Registry {
public:
template <typename Ret, typename ...Args>
void set (std::string name, Ret (*fun) (Args...)) {
funs[name].reset (new ConcreteFunMeta<Ret, Args...> (fun));
}
boost::any invoke (std::string name, std::string args) const {
const auto it = funs.find (name);
if (it == funs.end())
throw std::runtime_error ("meh");
return it->second->call (args);
}
private:
// You could use a multimap to support function overloading.
std::map<std::string, std::shared_ptr<FunMeta>> funs;
};
One could even think of supporting function overloading with this, using a multimap and dispatching decisions based on what content is on the passed arguments.
Here's how to use it:
int main () {
Registry reg;
reg.set ("select_it", select_string);
std::cout << boost::any_cast<std::string> (reg.invoke ("select_it", "0 John Wayne")) << '\n'
<< boost::any_cast<std::string> (reg.invoke ("select_it", "1 John Wayne")) << '\n';
}
If you can use boost, then here's an example of what I think you're trying to do ( although might work with std as well, I stick with boost personally ):
typedef boost::function<void ( MyClass&, const std::vector<std::string>& ) MyFunction;
std::map<std::string, MyFunction> dispatch_map;
namespace phx = boost::phoenix;
namespace an = boost::phoenix::arg_names;
dispatch_map.insert( std::make_pair( "someKey", phx::bind( &MyClass::CallBack, an::_1, phx::bind( &boost::lexical_cast< int, std::string >, phx::at( an::_2, 0 ) ) ) ) );
dispatch_map["someKey"]( someClass, std::vector< std::string >() );
However, as this sort of nesting quickly becomes fairly unreadable, it's usually best to either create a helper ( free function, or better yet a lazy function ) that does the conversion.
If I understand you correctly, you want to register void MyClass::Foo(int) and void MyClass::Bar(float), accepting that there will be a cast from std::string to int or float as appropriate.
To do this, you need a helper class:
class Argument {
std::string s;
Argument(std::string const& s) : s(s) { }
template<typename T> operator T { return boost::lexical_cast<T>(s); }
};
This makes it possible to wrap both void MyClass::Foo(int) and void MyClass::Bar(float) in a std::function<void(MyClass, Argument))>.
Interesting problme. This is indeen not trivial in C++, I wrote a self-contained implementation in C++11. It is possible to do the same in C++03 but the code would be (even) less readable.
#include <iostream>
#include <sstream>
#include <string>
#include <functional>
#include <vector>
#include <cassert>
#include <map>
using namespace std;
// string to target type conversion. Can replace with boost::lexical_cast.
template<class T> T fromString(const string& str)
{ stringstream s(str); T r; s >> r; return r; }
// recursive construction of function call with converted arguments
template<class... Types> struct Rec;
template<> struct Rec<> { // no parameters
template<class F> static void call
(const F& f, const vector<string>&, int) { f(); }
};
template<class Type> struct Rec< Type > { // one parameter
template<class F> static void call
(const F& f, const vector<string>& arg, int index) {
f(fromString<Type>(arg[index]));
}
};
template<class FirstType, class... NextTypes>
struct Rec< FirstType, NextTypes... > { // many parameters
template<class F> static void call
(const F& f, const vector<string>& arg, int index) {
Rec<NextTypes...>::call(
bind1st(f, fromString<FirstType>(arg[index])), // convert 1st param
arg,
index + 1
);
}
};
template<class... Types> void call // std::function call with strings
(const function<void(Types...)>& f, const vector<string>& args) {
assert(args.size() == sizeof...(Types));
Rec<Types...>::call(f, args, 0);
}
template<class... Types> void call // c function call with strings
(void (*f)(Types...), const vector<string>& args) {
call(function<void(Types...)>(f), args);
}
// transformas arbitrary function to take strings parameters
template<class F> function<void(const vector<string>&)> wrap(const F& f) {
return [&] (const vector<string>& args) -> void { call(f, args); };
}
// the dynamic dispatch table and registration routines
map<string, function<void(const vector<string>&)> > table;
template<class F> void registerFunc(const string& name, const F& f) {
table.insert(make_pair(name, wrap(f)));
}
#define smartRegister(F) registerFunc(#F, F)
// some dummy functions
void f(int x, float y) { cout << "f: " << x << ", " << y << endl; }
void g(float x) { cout << "g: " << x << endl; }
// demo to show it all works;)
int main() {
smartRegister(f);
smartRegister(g);
table["f"]({"1", "2.0"});
return 0;
}
Also, for performances, it's better to use unordered_map instead of map, and maybe avoid std::function overhead if you only have regular C functions. Of course this is only meaningful if dispatch time is significant compared to functions run-times.
No, C++ provides no facility for this to occur.