In C++, is there some equivalent of variadic template with values instead of typename or class?
Inside a method of a template class, the idea is to use values which are specified in the declaration of the instance, without going through a constructor.
That could be something like that (correct syntax not yet found):
template <class T, "some variadic value syntax...">
class Sample
{
public:
T val() { return T("some variadic value syntax..."); }
};
Sample <std::string> a; // a.val() returns ""
Sample <std::string, "foo"> b; // b.val() returns "foo"
Sample <std::string, 4, 'a'> c; // c.val() returns "aaaa"
Currently, the equivalent is done with preprocessing macros that I would like to eradicate and replace with templates.
Any other idea is welcome, as long as:
- it does not use macros,
- it uses up to C++17 but not more recent,
- there is no need to pass the values to a constructor,
- we don’t store the values inside the object instance,
- the constructor of the object may not have been called yet (static object inside a not-yet-initialized module),
- allow any number of values, including zero.
7
This syntax isn’t viable, because most types can’t be template parameters. Among other things, you can’t pass string literals (there are workarounds, but they don’t work for your case).
The only viable solution is to pass a functor, e.g. a lambda:
template <class T, auto F>
class Sample
{
public:
T val() { return F(); }
};
Sample<std::string, []{return std::string{};}> a; // a.val() returns ""
Sample<std::string, []{return std::string("foo");}> b; // b.val() returns "foo"
Sample<std::string, []{return std::string(4, 'a');}> c; // c.val() returns "aaaa"
But this requires C++20. Pre-C++20 you’d have to replace lambdas with functions (or functor classes), so the syntax wouldn’t look as good.
You can use the placeholder type auto
as shown below. Note that string literals are not allowed to be template arguments in current c++. So the second example Sample <std::string, "foo"> b;
will never work because here "foo"
cannot be passed. You can use user defined literals as a workaround for that.
template <class T, auto...Vs>
class Sample
{
public:
T val() { return T(Vs...); }
};
7