Get typedef from parameter pack - c++

I have a struct of this form:
template <typename T>
struct X
{
using value = T;
};
I am passing one or more of these to a template function like this:
template <typename... Ts>
void Func(Ts... ts);
What I really want is to explicitly list the Xs and have the function parameter types be the values of the Ts. How would I do that?

The following works for me.
template <typename T>
struct X
{
using value = T;
};
template <typename T>
struct Y
{
using value = T*;
};
template <typename... Ts>
void Func(typename Ts::value... ts)
{
}
int main()
{
Func<X<int>, Y<double>>(10, nullptr);
}

Related

Is there a way to store argument's type from templated method at compile time?

I got a weird one. I am trying to find a way to store every templated method's argument type to make it avaiable to class' users. A simple example may be:
template <typename... Ts>
struct Types {};
template <typename... Lhs, typename... Rhs>
constexpr auto operator+(Types<Lhs...>, Types<Rhs...>) {
return Types<Lhs..., Rhs...>{};
}
class User {
public:
template <typename Event, typename... New, typename... Old>
void run(const Event& event) {
// Something along the lines of:
types_<New...> = types_<Old...> + Types<Event>{};
/* Do stuff.. */
}
private:
template <typename... T>
static constexpr Types<T...> types_{};
};
I'm trying to store every Event type from each generated run() method, basically I'm looking for the variadic template's arguments <T...> form the types_ attribute. Is this even allowed by the language?
P.S. The Types struct is just a failed attempt to hopefully makes the intent of the question clear, any other solution would be more than welcome.
This reminded me of TypeList template structure which has Head and Tail elements
#include <iostream>
#include <typeinfo>
// List declaration
template <typename... Types>
struct TypeList;
//default specialization
template <typename H, typename... T>
struct TypeList<H, T...>
{
using Head = H;
using Tail = TypeList<T...>;
static const int Length = 1 + sizeof...(T);
};
//empty list specialization
template<>
struct TypeList<>
{
static const int Length = 0;
};
// add element to the top
template<typename H, typename TL>
struct Cons;
template<typename H, typename... Types>
struct Cons<H, TypeList<Types...>>
{
using type = TypeList<H, Types...>;
};
// concat two TypeLists
template<typename TL1, typename TL2>
struct Concat;
template<typename... Ts1, typename... Ts2>
struct Concat<TypeList<Ts1...>, TypeList<Ts2...>>
{
using type = TypeList<Ts1..., Ts2...>;
};
// print TypeList
template<typename TL>
void printTypeList(std::ostream& os)
{
os << typeid(typename TL::Head).name() << '\n';
printTypeList<typename TL::Tail>(os);
}
template<>
void printTypeList<TypeList<>>(std::ostream& os) {}
int main()
{
using TL1 = TypeList<double, float, int, char>;
using TL2 = TypeList<bool, int, bool>;
using TL3 = Cons<int, TL2>::type;
using TL4 = Concat<TL1, TL3>::type;
printTypeList<TL4>(std::cout);
return 0;
}
UPD
I tried to impliment TypeList strategy to your problem but the best I can do to put all types at run-time into std::string...
#include <iostream>
#include <typeinfo>
#include <string>
// List declaration
template <typename... Types>
struct TypeList;
//default specialization
template <typename H, typename... T>
struct TypeList<H, T...>
{
using Head = H;
using Tail = TypeList<T...>;
};
//empty list specialization
template<>
struct TypeList<> {};
template<typename TL>
void save_type_to_string(std::string& s)
{
s.append(typeid(typename TL::Head).name()).append("\n");
save_type_to_string<typename TL::Tail>(s);
}
template<>
void save_type_to_string<TypeList<>>(std::string& s) {}
class User {
public:
template <typename... Event>
void run(const Event... event) {
save_type_to_string<TypeList<Event...>>(types);
}
void print()
{
std::cout << types;
}
private:
std::string types;
};
int main()
{
User u;
u.run((int) 10, (long) 0.1, (bool) true);
u.run((int)10, (bool)true);
u.print();
return 0;
}

std::tuple of std::shared_ptr of template parameter pack

I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.

Function template taking a template non-type template parameter

How does one take a templated pointer to a member function?
By templated I mean that the following types are not known in advance:
template param T is class of the pointer to member
template param R is the return type
variadic template param Args... are the parameters
Non-working code to illustrate the issue:
template <???>
void pmf_tparam() {}
// this works, but it's a function parameter, not a template parameter
template <class T, typename R, typename... Args>
void pmf_param(R (T::*pmf)(Args...)) {}
struct A {
void f(int) {}
};
int main() {
pmf_tparam<&A::f>(); // What I'm looking for
pmf_param(&A::f); // This works but that's not what I'm looking for
return 0;
}
Is it possible to achieve the desired behavior in C++11?
I don't think this notation is possible, yet. There is proposal P0127R1 to make this notation possible. The template would be declared something like this:
template <auto P> void pmf_tparam();
// ...
pmf_tparam<&S::member>();
pmf_tparam<&f>();
The proposal to add auto for non-type type parameters was voted into the C++ working paper in Oulu and the result was voted to become the CD leading towards C++17 also in Oulu. Without the auto type for the non-type parameter, you'd need to provide the type of the pointer:
template <typename T, T P> void pmf_tparam();
// ...
pmf_tparam<decltype(&S::member), &S::member>();
pmf_tparam<decltype(&f), &f>();
As you've not said really what you are after in the function, the simplest is:
struct A {
void bar() {
}
};
template <typename T>
void foo() {
// Here T is void (A::*)()
}
int main(void) {
foo<decltype(&A::bar)>();
}
However if you want the signature broken down, I'm not sure there is a way to resolve the types directly, however you can with a little indirection...
struct A {
void bar() {
std::cout << "Call A" << std::endl;
}
};
template <typename R, typename C, typename... Args>
struct composer {
using return_type = R;
using class_type = C;
using args_seq = std::tuple<Args...>;
using pf = R (C::*)(Args...);
};
template <typename C, typename C::pf M>
struct foo {
static_assert(std::is_same<C, composer<void, A>>::value, "not fp");
typename C::return_type call(typename C::class_type& inst) {
return (inst.*M)();
}
template <typename... Args>
typename C::return_type call(typename C::class_type& inst, Args&&... args) {
return (inst.*M)(std::forward<Args...>(args...));
}
};
template <class T, typename R, typename... Args>
constexpr auto compute(R (T::*pmf)(Args...)) {
return composer<R, T, Args...>{};
}
int main() {
foo<decltype(compute(&A::bar)), &A::bar> f;
A a;
f.call(a);
}
The above should do what you are after...
What you can do is
template <template T, T value>
void pmf_tparam() {}
and then
pmf_tparam<decltype(&A::f), &A::f>();
The problem is not knowing the type of the argument and wanting a template argument of that type.
With an additional decltype (still in the templated parameter), this works:
#include <iostream>
using namespace std;
template <typename T, T ptr>
void foo (){
ptr();
}
void noop() {
cout << "Hello" << endl;
}
int main() {
//Here have to use decltype first
foo<decltype(&noop), noop>();
return 0;
}

Access type member

In my example I have a class Foo<T>. In my function test I need to get the template parameter of Foo otherwise the normal type. First I started to use std::conditional but forgot that the template parameters must all be valid, no matter which one is picked. Is the only way to create a type-specialisation for non-Foo types?
Example
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const T& a)
{
// actually I would have used !is_foo<T>::value for the first arg
// but this check is fine to minimise the example
using MY_TYPE = typename std::conditional<
std::is_same<T, int>::value,
T,
typename T::M>::type; // <---Error: error: type 'int' cannot be used prior to '::' because it has no members
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
Well you could make an UnFoo helper to get the right type for you:
template <typename T>
struct UnFoo {
using type = T;
};
template <typename T>
struct UnFoo<Foo<T>> {
using type = T;
};
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename UnFoo<T>::type; //maybe with a helper to get rid of typename
}
Another option would be to write an overload for Foo<T> and have it delegate to the other function, but that depends on what your real test function does.
You can do some void_t magic to allow SFINAE to figure help you out:
#include <type_traits>
#include <iostream>
#include <typeinfo>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
// primary template handles types that have no nested ::T member:
template< class T, class = void_t<> >
struct M_or_T { using type = T; };
// specialization recognizes types that do have a nested ::T member:
template< class T >
struct M_or_T<T, void_t<typename T::M>> { using type = typename T::M; };
template <typename T>
void test(const T& a)
{
using MY_TYPE = typename M_or_T<T>::type;
std::cout << typeid(MY_TYPE).name() << "\n";
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
What happens is that the second overload of M_or_T substitution fails for int (and for any type without a type member M) and thus the first overload is chosen. For types which have a type member M, a more specialized second overload is chosen.
#include <type_traits>
template <typename TYPE>
class Foo
{
public:
using M = TYPE;
};
template <typename T>
void test(const Foo<T>& a)
{
using MY_TYPE = Foo<T>::M;
testOther<MY_TYPE>(a);
}
template <typename T>
void test(const T& a)
{
using MY_TYPE = T;
testOther<MY_TYPE>(a);
}
template <typename T, typename S>
void testOther(const S& a)
{
// do stuff
}
int main()
{
test(Foo<int>()); // MY_TYPE must be int
test(int()); // MY_TYPE must be int
return 0;
}
I'm not exactly sure what you wanted, but I hope this is what you wanted. It might be a bit off. I didn't compile this.

Is it possible to obtain a type from decltype?

decltype returns a full type of an expression/entity. Is it possible to get only type?
For example, is it possible to make p to have type T in this case?
class T;
T t;
const T& tt = t;
decltype(tt) p; //decltype makes this const T& too as same as tt
It depends on entirely on what you want to do in the cases of cv T* and cv T[N]. If in all of those cases you just want T, then you'll need to write a type trait:
template <typename T>
struct tag { using type = T; };
template <typename T>
struct just_t
: std::conditional_t<std::is_same<std::remove_cv_t<T>,T>::value,
tag<T>,
just_t<std::remove_cv_t<T>>>
{ };
template <typename T>
struct just_t<T*> : just_t<T> { };
template <typename T>
struct just_t<T&> : just_t<T> { };
template <typename T, size_t N>
struct just_t<T[N]> : just_t<T> { };
template <typename T>
struct just_t<T[]> : just_t<T> { };
If you're okay with pointers staying as they are and arrays decaying into pointers, then simply:
template <typename T>
using just_t = std::decay_t<T>;