Unlike function declarations with parameter packs, I've found that classes require the type for each argument in the angle brackets...
Component<IntegerPair, int, int> temp(40, 5);
...which seems redundant. Here's how I defined Component:
template<typename T, class... T_Args>
class Component
{
public:
Component(T_Args... args)
: m_data(args...)
{}
T m_data;
};
Is there a way to remove int, int from the above statement?
If so, is it ok to remove it?
Also, is my way of instantiation m_data safe? When using
std::forward<T_Args>(args)... my compiler told me I didn't have a
constructor that could convert all of the argument types.
One way is to make the constructor a template:
#include <utility>
struct IntegerPair {
IntegerPair(int, int) {}
};
template<typename T>
class Component
{
public:
template<typename... T_Args>
Component(T_Args&&... args)
: m_data(std::forward<T_Args>(args)...)
{}
T m_data;
};
int main()
{
Component<IntegerPair> c {1,2};
}
This is functionally equivalent to std::vector and its member function emplace_back. It's perfectly ok, IMO. The error messages are pretty cryptic, as usual in template constructs like this, but this can be mitigated with an appropriate static_assert.
template parameter deduction only work for function calls so the basic pattern to achieve what you want looks like this:
template<typename T, class... T_Args>
Component<T, T_Args...> makeComponent(T_Args&&... args) {
return Component<T, T_Args...>(std::forward<T_Args>(args)...);
}
Usage:
auto c = makeComponent<IntegerPair>(1, 1)
Related
I would like to have the following code in c++17:
#include <iostream>
#include <string>
#include <type_traits>
#include <functional>
class Foo;
template<class T>
class Bar {
public:
std::function<T(Foo&)> m_fn;
template<class Fn>
Bar(Fn fn) : m_fn(fn) {};
T thing(Foo &foo) const {
return m_fn(foo);
}
};
template<class Fn>
Bar(Fn) -> Bar<decltype(std::invoke(std::declval<Fn>(),
std::declval<Foo&>()))>;
class Foo {
public:
Foo() {};
template<class T>
std::vector<T> do_thing(const Bar<T> &b) {
std::vector<T> r;
r.push_back(b.thing(*this));
return r;
}
};
std::string test(Foo &) {
return "hello";
}
int main() {
Foo foo = Foo();
// works
std::vector<std::string> s = foo.do_thing(Bar{test});
// cant deduce T parameter to do_thing
std::vector<std::string> s = foo.do_thing({test});
}
But compiling this gives me "couldn't deduce template parameter âTâ" on the call to do_thing.
Having do_thing(Bar{test}) fixes this and works fine but equates to some ugly code in the real code equivalent. I would like to have do_thing({test}) or do_thing(test) implicitly construct a Bar and pass that as the argument if possible.
I also don't want to forward declare a variable to pass into do_thing either
Is there some way to guide the inference of template argument T so that the call to do_thing can stay clean?
Edit:
Sorry for the late edit, but the arguments to the Bar constructor are over simplified in the example I included. In reality, there is an extra parameter std::optional<std::string> desc = std::nullopt and that might change in the future (although unlikely). So constructing the Bar inside do_thing would be a bit hard to maintain...
would like to have do_thing({test}) or do_thing(test) implicitly construct a Bar and pass that as the argument if possible.
Unfortunately, when you call do_thing({test}) or do_thing(test), test (or {test}) isn't a Bar<T> object. So the compiler can't deduce the T type and can't construct a Bar<T> object.
A sort of chicken-and-egg problem.
The best I can imagine is to add, in Foo, a do_test() method as follows
template<typename T>
auto do_thing (T const & t)
{ return do_thing(Bar{t}); }
This way you can call (without graphs)
std::vector<std::string> s = foo.do_thing(test);
You get the same result as
std::vector<std::string> s = foo.do_thing(Bar{test});
-- EDIT --
The OP ask
is there any way of preserving the {test} brace syntax? maybe with initializer_list or something?
Yes... with std::initializer_list
template<typename T>
auto do_thing (std::initializer_list<T> const & l)
{ return do_thing(Bar{*(l.begin())}); }
but, this way, you accept also
std::vector<std::string> s = foo.do_thing(Bar{test1, test2, test3});
using only test1
Maybe a little better... another way can be through a C-style array
template <typename T>
auto do_thing (T const (&arr)[1])
{ return do_thing(arr[0]); }
This way you accept only an element.
This happens because {} is not an expression and can only be used in limited ways while doing argument deduction, the parameter must have specific forms in order to succeed.
The allowed parameters types that can be used to deduce template parameters when {} is involved are better expanded in [temp.deduct.call]/1, two of the examples extracted from the cited part of the standard are:
template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int
In your example the deduction guide is not used to deduce the T for {test} for the same as above.
foo.do_thing(Bar{test});
is your direct option without using additional functions.
I have a Base class:
class Base() {
public:
Base(int, int);
~Base();
};
I have multiple classes that inherit from Base:
class childA : public Base {
public:
childA(int, int, string);
~childA();
};
childA::childA(int x, int y, string str) : Base (x, y)
{
// do something here
}
Same for childB, childC, etc
I want to know if it's possible to create childA, childB or childC using a string. I heard about variadic tempaltes but I don't really understand how to use it.
Variadic template is a template, which can take an arbitrary number of template arguments of any type. Both the functions could be variadic since dawn of C language (printf function, for example), then macros and now - templates.
You can declare it like this:
template<typename... Arguments> class Variadic;
then specialize it with any number of arguments, including zero:
Variadic<double> instance;
Variadic<double, std::string> instance;
Variadic<> instance;
Then you may use the argument list, known as argument pack, like this:
template<typename... Arguments> void SampleFunction(Arguments... parameters);
Just as in case of variadic functions, the argument pack can be preceded by concrete arguments:
template<typename First, typename... Rest> class BunchOfValues;
There is classic example of variadic template in STL: std::tuple. Some compilers do not support this feature fully or do not support at all, and in their case tuple is implemented through metaprogramming and macro definitions.
There is no direct way in C++ to select particular argument from the list, like it is possible with variadic functions. It's possible to use recursion to iterate through them in one direction:
template<typename T> foo(T first)
{
// do something;
}
template<typename T, typename U, typename ... Args> foo(T first, U second, Args... Rest)
{
// do something with T
foo(second, Rest...);
}
Usually iteration would rely on function overloading, or - if the function can simply pick one argument at a time - using a dumb expansion marker:
template<typename... Args> inline void pass(Args&&...) {}
which can be used as follows:
template<typename... Args> inline void expand(Args&&... args) {
pass( some_function(args)... );
}
expand(42, "answer", true);
which will expand to something like:
pass( some_function(arg1), some_function(arg2), some_function(arg3) etc... );
The use of this "pass" function is necessary, since the expansion of the argument pack proceeds by separating the function call arguments by commas, which are not equivalent to the comma operator. some_function(args)...; will never work. Moreover, this above solution will only work when the return type of some_function is not void. Furthermore, the some_function calls will be executed in an unspecified order, because the order of evaluation of function arguments is undefined. To avoid the unspecified order, brace-enclosed initializer lists can be used, which guarantee strict left-to-right order of evaluation. To avoid the need for a not void return type, the comma operator can be used to always yield 1 in each expansion element.
struct pass {
template<typename ...T> pass(T...) {}
};
pass{(some_function(args), 1)...};
The number of arguments in argument pack can be determined by sizeof...(args) expression.
As of creating initializers that use calls name it is possible only if name is defined at time of writing the code. There stingizer operator # in preprocessor that can be used, e.g.
#define printstring( x ) printf(#x "\n")
printstring( This a dumb idea );
will generate code (assuming that C++ automatically joins string literals):
printf("This a dumb idea \n")
You can declare something like this:
template<typename T> class moniker
{
public:
moniker(const char* tname);
}
#define declare_moniker(type, name) moniker<type> name(#type)
How would variadic macro definitions and variadic template interact? I'm not sure. Compiler I have at hand failed, but it isn't C++11. Try that, if interested.
There might be typeid operator supporeted, depending on compiler settings.
const std::type_info& ti1 = typeid(A);
std::type_info got method name(), but string it returns is implementation dependant: http://en.cppreference.com/w/cpp/types/type_info/name
In c++14 you could create some helper struct to determine each character of the string you pass at compile-time and to forward it to a type. However string you pass need to be stored in variable with linkage to let compiler to use it as a non-type template parameter:
#include <utility>
#include <type_traits>
template <char... Cs>
struct string_literal { };
template <class T, T &, class>
struct make_string_literal_impl;
template <class T, T &Cs, std::size_t... Is>
struct make_string_literal_impl<T, Cs, std::index_sequence<Is...>> {
using type = string_literal<Cs[Is]...>;
};
template <class T, T &>
struct make_string_literal;
template <class T, std::size_t N, T (&Cs)[N]>
struct make_string_literal<T[N], Cs>: make_string_literal_impl<T[N], Cs, std::make_index_sequence<N>> {
};
struct Base {
Base(int, int) { }
~Base() { }
};
template <class>
struct Child: Base {
using Base::Base;
};
constexpr char const str[] = "abc";
int main() {
Child<make_string_literal<decltype(str), str>::type> c(1, 1);
}
[live demo]
In C++11 you can instantiate std::function like this:
std::function<void(int)> f1;
std::function<int(std::string, std::string)> f2;
//and so on
But while there is plenty of info on variadic templates on the web, I fail to find any articles on how to write std::function-like template which would accept parenthesized arguments.
Could anyone please explain the syntax and its limitations or at least point to an existing explanation?
There's nothing special about it, it's an ordinary function type. When you declare a function like this:
int foo(char a, double b)
Then its type is int (char, double). One way of "unwrapping" the individual argument types and return type is to use partial template specialisation. Basically, std::function looks something like this:
template <class T>
struct function; // not defined
template <class R, class... A>
struct function<R (A...)>
{
// definition here
};
Pretty much like any other template, since int(std::string, std::string) is just a type.
Here's a really naive example that compiles:
template <typename FType>
struct Functor
{
Functor(FType* fptr) : fptr(fptr) {}
template <typename ...Args>
void call(Args... args)
{
fptr(args...);
}
private:
FType* fptr;
};
void foo(int x, char y, bool z) {}
int main()
{
Functor<void(int, char, bool)> f(&foo);
f.call(1, 'a', true);
//f.call(); // error: too few arguments to function
}
In reality you'd have a specialisation on FType being ReturnType(ArgTypes...), though my naive example will already give you the validation you need if you try to invoke it in in compatible ways.
How to define method signature so it will accept same number of arguments as variadic template class definition? For example how to define an Array class:
template<typename T, int... shape>
class Array
{
public:
T& operator () (???);
};
So you will be able to call it like this:
Array<int, 3, 4, 5> a;
a(1, 2, 3) = 2;
template<class T, int...Shape>
class Array {
template<int>using index_t=int; // can change this
public:
T& operator()(index_t<Shape>... is);
};
or:
template<class T, int...Shape>
class Array {
public:
T& operator()(decltype(Shape)... is);
};
or:
template<class T, int...Shape>
class Array {
public:
T& operator()(decltype(Shape, int())... is);
};
if you want to be able to change the type of the parameter to be different than Shape.
I find the decltype harder to understand a touch than the using, especially if you want to change the type of the parameter to be different than int.
Another approach:
template<class T, int...Shape>
class Array {
public:
template<class...Args,class=typename std::enable_if<sizeof...(Args)==sizeof...(Shape)>::type>
T& operator()(Args&&... is);
};
which uses SFINAE. It does not enforce that the Args are integer types however. We could add another clause if we wanted to (that all of the Args are convertible to int, say).
Yet another approach is to have your operator() take a package of values, like a std::array<sizeof...(Shape), int>. Callers would have to:
Array<double, 3,2,1> arr;
arr({0,0,0});
use a set of {}s.
A final approach would be:
template<class T, int...Shape>
class Array {
public:
template<class...Args>
auto operator()(Args&&... is) {
static_assert( sizeof...(Args)==sizeof...(Shapes), "wrong number of array indexes" );
}
};
where we accept anything, then generate errors if it is the wrong number of arguments. This generates very clean errors, but does not do proper SFINAE operator overloading.
I would recommend tag dispatching, but I don't see a way to make it much cleaner than the SFINAE solution, with the extra decltype and all, or better error messages than the static_assert version on the other hand.
I assume you want your arguments to be all of the same type, probably using an integer type (I'll just use int). An easy approach is to leverage the parameter pack you already have:
template <int>
struct shape_helper { typedef int type; };
template <typename T, int... Shape>
class Array
{
public:
T& operator()(typename shape_helper<Shape>::type...);
};
I'm trying to expand a class's variadic template type list within a child method as such:
template<typename... P>
struct Foo
{
template<P...> // error C3522: 'P' : parameter
// pack cannot be expanded in this context
static void Bar(P... a){}
};
What is wrong with this code, or is it just a MSVS '12: Nov. '12 CTP bug?
(Yes, I know the explicit template specialization in this example is redundant.)
The above is the simplest case that I get to reproduce the error. The full code is:
template<typename FuncSignature>
class Callback;
template<typename R, typename... P>
class Callback<R (P...)>
{
public:
Callback() : func(0), obj(0) {}
Callback& operator=(const Callback& rhs)
{ obj = rhs.obj; func = rhs.func; return *this; }
private:
typedef R (*FuncType)(const void*, P...);
Callback(FuncType f, const void* o) : func(f), obj(o) {}
private:
FuncType func;
const void* obj;
template<typename FR, typename... FP>
friend class FreeCallbackFactory;
};
template<typename R, typename... P>
class FreeCallbackFactory
{
private:
template<R (*Func)(P...)>
static R Wrapper(const void*, P... a)
{
return (*Func)(a...);
}
public:
template<R (*Func)(P...)>
inline static Callback<R (P...)> Bind()
{
return Callback<R (P...)>
(&FreeCallbackFactory::Wrapper<Func>, 0);
}
};
template<typename R, typename... P>
inline FreeCallbackFactory<R, P...>
GetCallbackFactory(R (*)(P...))
{
return FreeCallbackFactory<R, P...>();
}
void Test(){}
int main(int argc, char** argv){
Callback<void ()> cb = GetCallbackFactory(&Test).Bind<&Test>()
}
It compiles fine in g++ so I'm assuming just a compiler bug, and continued findings still only point to this, are there any possible workarounds for this other than explicitly expanding them out one by one?
Edit: This has been reported to the compiler team as a bug and a patch will be in the next release of the compiler. [Link]
The code looks correct put I doubt that it does what you intended it to do: The declaration
template <P...>
static void Bar(P... a);
declares a function taking P... values as template argument and as function argument. That is, the elements of P need to be of a type allowing non-type parameters (e.g., integers, pointers, or references) and you'd need to provide their respective values as template parameters when calling the function. The call to a function like this would look something like this (although it seems neither gcc nor clang require the template parameters to be passed):
Foo<int, int>::Bar<1, 2>(3, 4);
That said, based on the error messages generated by both gcc and clang it seems that they won't let you create a specialization of member function templates but I haven't verified this in the standard. I think, you should probably just leave out the template declaration and use
static void Bar(P... a);
To me the code does not look correct. The pack expansion P... expands to a set of types. Depending on what you aim to achieve the correct thing to do would be to remove the template<P...> part, in which case each class template instance has one Bar() method with the same parameters as the class. The other would be that this is an unrelated parameter pack in which case an unbounded set of methods is generated, in that case you must declare the method something like:
template<typename... U> static void Bar(U...);
reusing the name P would not be very useful, I guess.