Related
I get a tuple of types (e.g. std::tuple) and I want to create tuple of vectors given by these types. I wrote this, but when I use it as I want, it doesn't work, I get this error:
Error (active) E0730 type "types" is not a class template
I am pretty new to variadic templates so I don't know how to do it properly.
using namespace std;
template <template <typename...> typename Tuple, typename... Types>
class vertices
{
public:
tuple<vector<Types...> > v;
};
int main{
using types = tuple<int, string, double>;
vertices<types> ver;
}
In your code, Tuple is a template template parameter, so it expects a template. types is not a template but a concrete type, so it is not usable. Instead what you can do is just take in the tuple, and then using a helper meta function get the type for the member like
// no definition since it is only used in unevaluated contexts, just used as a helper to get the type converted
template <typename... Types>
std::tuple<std::vector<Types>...> tuple_to_tuple_of_vectors(std::tuple<Types...>);
template <typename Tuple>
class vertices
{
public:
using tuple_type = decltype(tuple_to_tuple_of_vectors(std::declval<Tuple>()));
tuple_type v;
};
int main ()
{
using types = tuple<int, string, double>;
vertices<types> ver;
}
From your question, it appears your requirement is just to be able to conveniently express the type
tuple<vector<int>, vector<string>, vector<double>>
as
vertices<tuple<int, string, double>>
This can be achieved using a variable template. All we need is to take a type (that's a tuple), and unpack that tuple into a vector. Since a type is not a variadic pack, we need another level of indirection to get the types within the tuple. #NathanOliver's answer shows a nice way to do that, using the declaration of a function-template. As pointed out, since all we need is type transformations, the function doesn't need a definition, the declaration says it all: the argument type is the input type, and the return type is the output type.
template <typename... Types>
auto unpack(tuple<Types...>) -> tuple<vector<Types>...> ;
template <typename Tuple>
using vertices = decltype(unpack(declval<Tuple>()));
static_assert(std::is_same<
vertices<tuple<int, string, double>>,
tuple<vector<int>, vector<string>, vector<double>>>{});
Your first template parameter is a template template parameter, but types is not a template, it is a type. Also you have the ... in the wrong place. You need tuple<vector<Types>...>, otherwise Types is expanded as parameters for vector.
The following comes with a disclaimer: I know a bit of tempaltes with C++11, but I am rather ignorant about newer features, so there might be more elegant ways to write the same.
As base template you can use:
template <typename... Types>
struct vertices
{
using tuple_of_vectors_t = tuple<vector<Types>... >;
tuple_of_vectors_t v;
};
And then for tuples:
template <typename... Types>
struct vertices<std::tuple<Types...>> : vertices<Types...> {};
Complete example:
#include <tuple>
#include <vector>
#include <iostream>
#include <type_traits>
using namespace std;
template <typename... Types>
struct vertices
{
using tuple_of_vectors_t = tuple<vector<Types>... >;
tuple_of_vectors_t v;
};
template <typename... Types>
struct vertices<std::tuple<Types...>> : vertices<Types...> {};
int main () {
using types = tuple<int, string, double>;
vertices<types> ver;
std::cout << std::is_same_v< vertices<types>::tuple_of_vectors_t,
std::tuple< std::vector<int>,
std::vector<std::string>,
std::vector<double>
>
>;
}
Output:
1
I'd like to use partial template specialization in order to 'break down' an array (which is created at compile time) into a parameter pack composed of its values (to interface with other structures I define in my code). The following (my first attempt) is not compiling
#include <array>
template <typename T, auto k> struct K;
template <typename T, std::size_t... A> struct K<T, std::array<std::size_t, sizeof...(A)>{A...}> {};
because the template argument std::array<long unsigned int, sizeof... (A)>{A ...} must not involve template parameters. As I understood it, it is not possible to provide non type parameters in a partial template specialization if they non-trivially depend on template parameters. Hence I attempted to work around this issue by containing the value in a type:
#include <array>
template <auto f> struct any_type;
template <typename T, typename array_wrapper> struct FromArr;
template <typename T, std::size_t... A>
struct FromArr<T, any_type<std::array<std::size_t, sizeof...(A)>{A...}>> {};
int main() {
FromArr<int, any_type<std::array<std::size_t, 2>{1, 2}>> d;
(void) d;
}
However, here, the partial template specialization fails when I'm trying to use it; the definition above does not match the way I use it, and I am unsure why. It fails with the following error:
file.cc: In function ‘int main()’:
file.cc:10:55: error: aggregate ‘FromArr<int, Any<std::array<long unsigned int, 2>{std::__array_traits<long unsigned int, 2>::_Type{1, 2}}> > d’ has incomplete type and cannot be defined
10 | FromArr<int, Any<std::array<std::size_t, 2>{1, 2}>> d;
Is it possible to work around this / use a different approach in order to interface the array as parameter pack?
Used Compiler
I use g++-10.0 (GCC) 10.0.1 20200124 (experimental) and compile via g++ -std=c++2a file.cc, c++2a is required because I use non-type template parameters.
Edit:
Description how the array is ment to be processed
In my real code I have got a structure which depends on -- among others -- a parameter pack (1). It would be nice if I were able to use an array (2) (which I have got in another piece of my code as a non-type template argument) to interface with that structure, as sketched in the code below.
template <int... s> struct toBeUsed; // (1)
template <std::size_t s, std::array<int, s> arr> struct Consumer { // (2)
toBeUsed<arr> instance; // This is what I would like to do
}
My Attempt is to write a helper struct as above FromStruct, which I can instantiate with an array in which I have a typedef FromStruct::type that provides toBeUsed with the correct arguments, similar to this example, which does what I want to do here with the types a std::tuple is composed of.
Link to the example
here I link the simplified usage example (2nd code block).
Inspired by #dfri 's answer, I transformed her / his solution to a version which can omit functions, but instead uses only one struct using partial template specialization for the std::integer_sequence which might also be interesting to others:
template <auto arr, template <typename X, X...> typename Consumer,
typename IS = decltype(std::make_index_sequence<arr.size()>())> struct Generator;
template <auto arr, template <typename X, X...> typename Consumer, std::size_t... I>
struct Generator<arr, Consumer, std::index_sequence<I...>> {
using type = Consumer<typename decltype(arr)::value_type, arr[I]...>;
};
Full example with usage:
#include <array>
/// Structure which wants to consume the array via a parameter pack.
template <typename StructuralType, StructuralType... s> struct ConsumerStruct {
constexpr auto operator()() const { return std::array{s...}; }
};
/// Solution
template <auto arr, template <typename X, X...> typename Consumer,
typename IS = decltype(std::make_index_sequence<arr.size()>())> struct Generator;
template <auto arr, template <typename X, X...> typename Consumer, std::size_t... I>
struct Generator<arr, Consumer, std::index_sequence<I...>> {
using type = Consumer<typename decltype(arr)::value_type, arr[I]...>;
};
/// Helper typename
template <auto arr, template <typename T, T...> typename Consumer>
using Generator_t = typename Generator<arr, Consumer>::type;
// Usage
int main() {
constexpr auto tup = std::array<int, 3>{{1, 5, 42}};
constexpr Generator_t<tup, ConsumerStruct> tt;
static_assert(tt() == tup);
return 0;
}
A C++20 approach
See OP's own answer or, for possibly instructive but more verbose (and less useful) approach, revision 2 of this answer.
A C++17 approach
(This answer originally contained an approach using a minor C++20 feature (that a lambda without any captures may be default constructed), but inspired by the original answer the OP provided a much neater C++20 approach making use of the fact that a constexpr std::array falls under the kind of literal class that may be passed as a non-type template parameter in C++20 (given restraints on its ::value_type), combined with using partial specialization over the index sequence used to unpack the array into a parameter pack. This original answer, however, made use of a technique of wrapping std::array into a constexpr lambda (>=C++17) which acted as a constexpr (specific) std::array creator instead of an actual constexpr std::array. For details regarding this approach, see revision 2 of this answer)
Following OP's neat approach, below follows an adaption of it for C++17, using a non-type lvalue reference template parameter to provide, at compile time, a reference to the array to the array to struct target.
#include <array>
#include <cstdlib>
#include <tuple>
#include <type_traits>
#include <utility>
// Parameter pack structure (concrete target for generator below).
template <typename StructuralType, StructuralType... s>
struct ConsumerStruct
{
// Use tuple equality testing for testing correctness.
constexpr auto operator()() const { return std::tuple{s...}; }
};
// Generator: FROM std::array TO Consumer.
template <const auto& arr,
template <typename T, T...> typename Consumer,
typename Indices = std::make_index_sequence<arr.size()> >
struct Generator;
template <const auto& arr,
template <typename T, T...> typename Consumer,
std::size_t... I>
struct Generator<arr, Consumer, std::index_sequence<I...> >
{
using type =
Consumer<typename std::remove_cv<typename std::remove_reference<
decltype(arr)>::type>::type::value_type,
arr[I]...>;
};
// Helper.
template <const auto& arr, template <typename T, T...> typename Consumer>
using Generator_t = typename Generator<arr, Consumer>::type;
// Example usage.
int main()
{
// As we want to use the address of the constexpr std::array at compile
// time, it needs to have static storage duration.
static constexpr std::array<int, 3> arr{{1, 5, 42}};
constexpr Generator_t<arr, ConsumerStruct> cs;
static_assert(cs() == std::tuple{1, 5, 42});
return 0;
}
Note that this approach places a restriction on the std::array instance in that it needs to have static storage duration. If one wants to avoid this, using a constexpr lambda which generates the array may be used as an alternative.
In C++, it's possible to use a type as a template parameter, e.g:
template <typename T>
void MyFn();
It's also possible to use a non-type as a template parameter in some cases, e.g.:
template <int64_t T>
void MyFn2();
My question is whether it's possible to have a "generic" template parameter that can be both? Like:
template <TypenameOrint64_t T>
void MyFn3();
such that both MyFn3<42> and MyFn3<double> would be acceptable.
An example of how I might use this:
template <typename ValType, ValType Head, ValType ...Tail>
struct ListS{
template <typename OutType, template <ValType ArgType> class Fn>
using MapHead = ListS<OutType, Fn<Head>::val, Tail...>;
};
template<int64_t N>
struct SquareS{
static constexpr const int64_t val = N * N;
};
using Sqrd = ListS<int64_t, 3, 4>::MapHead<int64_t, SquareS>;
static_assert(std::is_same<Sqrd, ListS<int64_t, 9, 4>>::value, "Values don't match");
The above is a very rough sketch of a compile-time list of values along with a single compile-time "function" on it. Would it be possible to make something like that also support lists of types, not just lists of non-type template param compatible values, without just duplicating all the code?
Is it possible to have a “generic” template parameter in C++, that can be either a non-type template parameter or a type?
Short answer: no.
Long answer.
No. The best I can imagine to mix types and values is wrap values in types, using std::integral_constant, by example.
So, your desired code, could be written (C++17) almost as follows
#include <utility>
template <typename ...>
struct ListS;
template <typename ValType, ValType Head, ValType ...Tail>
struct ListS<std::integral_constant<ValType, Head>,
std::integral_constant<ValType, Tail>...>
{
template <template <auto> class Fn, typename OutType = ValType>
using MapHead = ListS<std::integral_constant<OutType, Fn<Head>::value>,
std::integral_constant<OutType, Tail>...>;
};
template <auto N>
struct SquareS : public std::integral_constant<decltype(N), N*N>
{ };
int main ()
{
using T1 = ListS<std::integral_constant<long long, 3ll>,
std::integral_constant<long long, 4ll>>;
using T2 = T1::MapHead<SquareS>;
using T3 = ListS<std::integral_constant<long long, 9ll>,
std::integral_constant<long long, 4ll>>;
static_assert( std::is_same_v<T2, T3> );
}
Pre C++17 you can't use auto for the type of the template values so you should make some simple corrections.
You could use function overloading and the auto type deduction that came with C++17
to accomplish something similar.
template<typename myType>
auto myFn3(myType value){
return value;
}
template<auto value> //takes any non-type parameter
auto myFn3(){
return value;
}
int main(){
auto test1_normal = myFn3(3);
auto test1_cast = myFn3<double>(3); //able to perform a cast
auto test1_auto = myFn3<3>();
return 0;
}
Having a list of types as a variadic template argument, it's pretty easy to perform arbitrary type manipulation on them, to get a tuple of modified types as a result. E.g. to wrap each element with a custom wrapper class, one could do:
template<typename T> class Wrapper {};
template<typename ...Values>
using WrappedValues = std::tuple<Wrapper<Values>...>;
using NewTuple = WrappedValues<int, std::string, char>;
static_assert(std::is_same<NewTuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");
How to do the same, when having a specialization of std::tuple as an "input"? E.g. what should be placed instead of "???" to make following code compileable:
template<typename T> class Wrapper {};
template<typename Tuple>
using WrappedTupleElements = ???;
using NewTuple = WrappedTupleElements<std::tuple<int, std::string, char>>;
static_assert(std::is_same<NewTuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");
I know about the possibility to access types of tuple elements using std::tuple_element and recursive template instantiation, but I don't know how to gather types created this way into one tuple.
Preferred would be pure C++14 answer, but proposals that use C++17, widely available TSes, or external libraries (e.g. boost) are also welcome.
Why not to use additional struct template which allow specialization:
#include <string>
#include <tuple>
#include <type_traits>
template<typename T> class Wrapper {};
template<typename Tuple>
struct WrappedTupleElements;
template <class... Values>
struct WrappedTupleElements<std::tuple<Values...>> {
using type = std::tuple<Wrapper<Values>...>;
};
int main() {
using NewTuple = WrappedTupleElements<std::tuple<int, std::string, char>>::type;
static_assert(std::is_same<NewTuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");
}
[live demo]
A common idiom (e.g. boost mpl) is to employ the concept of metafunctions.
A metafunction is a template class which declares a type called result which yields the result type of applying the metafunction on the inputs.
#include <string>
#include <tuple>
#include <type_traits>
template<typename T> class Wrapper {};
namespace metafunction
{
template<class MetaFunction> using result_of = typename MetaFunction::result;
// meta-function which yields Wrapper<Element> from Element
// type: unary metafunction
// arg1 = the type to wrap
// returns Wrapper<arg1>
//
template<class Element>
struct apply_wrapper
{
using result = Wrapper<Element>;
};
template<class Tuple, template<class> class Function>
struct transform_elements;
// meta-function which takes a tuple and a unary metafunction
// and yields a tuple of the result of applying the metafunction
// to each element_type of the tuple.
// type: binary metafunction
// arg1 = the tuple of types to be wrapped
// arg2 = the unary metafunction to apply to each element_type
// returns tuple<result_of<arg2<element>>...> for each element in arg1
template<class...Elements, template<class> class UnaryMetaFunction>
struct transform_elements<std::tuple<Elements...>, UnaryMetaFunction>
{
template<class Arg> using function = UnaryMetaFunction<Arg>;
using result = std::tuple
<
result_of<function<Elements>>...
>;
};
}
int main() {
using input_type = std::tuple<int, std::string, char>;
using namespace metafunction;
using wrapped_tuple = result_of<transform_elements<input_type, apply_wrapper>>;
static_assert(std::is_same<wrapped_tuple, std::tuple<Wrapper<int>, Wrapper<std::string>, Wrapper<char>>>::value, "");
}
I would like to know whether it is possible to define a function type that takes n arguments, just by knowing n and the type of these arguments.
For example, we could have something like :
template<int N> struct test {
typedef void(*)(E,E,E,...) fct; //E is written N times
};
In C++11 it is easy to instanciate a variadic template with N times the same type using recursivity, but I have no idea how to translate that into a valid function pointer type.
As I type those words, the solution came to me. I will answer myself, so the knowledge can help someone in the future.
If you want a simpler solution, you could just make the function take a std::array<T, N>. Initialize the array directly within the parentheses to make it look mostly like a normal function call:
foo({1, 2, 3}) // to pass a std::array<int, 3>
While I was typing I suddenly envisioned the solution in C++11.
The trick is to use a generic Fct template type and specialise it a function type using variadic template type for the argument of the function "specialisation".
template< typename Fct, typename NewArg > struct functional_append_arg;
template< typename Ret, typename... Args, typename NewArg >
struct functional_append_arg< Ret(Args...), NewArg >
{ using type = Ret(Args...,NewArg); };
template< typename Ret, typename Arg, int N> struct functional_repeat_arg;
{ using type = functional_append_arg< functional_repeat_arg<Ret,Arg,N-1>::type, Arg >::type; };
template< typename Ret, typename Arg> struct functional_repeat_arg<Ret,Arg,0>;
{ using type = Ret(); }
We can take advantage of the indices trick here again in lieu of the recursive variadic technique.
#include <cstddef>
#include <utility>
template <typename T, std::size_t N>
struct repeat {
private:
/* Map any index to T. */
template <std::size_t>
using T_ = T;
/* Function pointer that takes Ts. */
template <typename... Ts>
using Fn = void (*)(Ts...);
/* A function returning void (*)(T...). */
template <std::size_t... Is>
static Fn<T_<Is>...> impl(std::index_sequence<Is...>);
public:
/* Get the return type of impl. */
using type = decltype(impl(std::make_index_sequence<N>()));
}; // repeat
static_assert(std::is_same<repeat<int, 5>::type,
void (*)(int, int, int, int, int)>::value, "");