Consider this minimal example:
template <typename T, typename U>
struct foo {};
template <template <typename...> class Bar>
struct converter
{
template <typename... Args>
converter(const Bar<Args...> &);
};
int main()
{
converter<foo> c(foo<int,double>()); // This works.
// converter<foo> c = foo<int,double>(); This fails
}
The commented-out line fails with both GCC 4.5 and 4.6, with a message like:
main.cpp:10:2: error: wrong number of template arguments (1, should be 2)
main.cpp:4:8: error: provided for template<class T, class U> struct foo
main.cpp: In function int main():
main.cpp:15:37: error: conversion from foo<int, double> to non-scalar type converter<foo> requested
If, instead of using variadic templates, the specific number of template parameters is used (i.e., 2 in this case) there are no errors. I'm a bit confused since I expected the two lines to be exactly equivalent: is this an expected behaviour?
Yes, this is supposed to work. It's a GCC error. GCC doesn't support C++0x variadic templates to the fullest yet (and to be fair, the specification is still constantly changing in details).
What you say "This works" is really declaring a function; it doesn't initialize an object, which was what you intended.
For what you intended, see 14.3.3p3 which describes how template<typename...> class Bar can match foo, and 14.8.2.5p9 which describes how foo<Args...> can match foo<int, double>.
template <typename T, typename U>
struct foo {};
struct converter
{
template <template <typename...> class Bar, class ...Args>
converter(const Bar<Args...> &){}
};
int main()
{
converter c1((foo<int,double>())); // This works.
converter c2 = foo<int,double>();// This works
}
Related
Here is MCVE (uncompilable) :-
#include <iostream>
#include <type_traits>
//-- library ---
template<class T,template<class>class Slot,class DefaultType>
class GetType{
template <typename C> static Slot<T> check( Slot<T>*);
template <typename> static DefaultType check(...);
public: using type=decltype(check<T>());
};
template<class T,template<class>class Slot,class DefaultType>
using X = typename GetType<T,Slot,DefaultType>::type;
Here is its usage :-
//--- user defined ---
class B {public: using MyType=int;};
class C{};
template<class T> using SlotCustom = typename T::MyType;
int main(){
using ShouldInt=X< B ,SlotCustom ,long>; //B::Mytype =int , result:int
using ShouldLong=X< C ,SlotCustom ,long>;//C::Mytype not exist, result:long
std::cout<< std::is_same_v<ShouldInt, int> <<std::cout; //should true
std::cout<< std::is_same_v<ShouldLong, long> <<std::cout; //should true
}
My objective is to create a library typedef X< Param1 ,SlotCustom ,DefaultType> that means as the following pseudo code:-
if ( SlotCustom<Param1> has meaning) return "SlotCustom<Param1>" ;
else return "DefaultType"; //i.e. by default
How to do it?
Here is a similar question.
The main difference is that X<T> there can be only a bool, and many things are hardcoded.
I am new to template specialization. The solution might be obvious, but I can't find it.
If I understand your question correctly, then your approach can be made to work, for example
template <template <class> class Slot, class DefaultType>
struct GetType
{
template <typename T>
static Slot<T>&& deduce(T&&);
static DefaultType&& deduce(...);
template <typename T>
using type = std::remove_reference_t<decltype(deduce(std::declval<T>()))>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<Slot, DefaultType>::template type<T>;
live demo here
The problem with your initial attempt was that the call to your check function in the expression for decltype() needed some argument for overload resolution to take place so that the SFINAE magic can happen. My example above relies on std::declval to introduce a dummy argument of the necessary type. Also, note that my helper functions use references rather than passing the types by value directly. This is so that it also works with types that are not copyable. Note that there will be problems if Slot<T> or the DefaultType are reference types themselves. One would have to, e.g., introduce additional wrapper types to deal with that…
Alternatively, you could use partial class template specialization to pick the correct type, for example:
template <class T, template <class> class Slot, class DefaultType, typename = void>
struct GetType
{
using type = DefaultType;
};
template <class T, template <class> class Slot, class DefaultType>
struct GetType<T, Slot, DefaultType, std::void_t<Slot<T>>>
{
using type = Slot<T>;
};
template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<T, Slot, DefaultType>::type;
live demo here
The trick here lies in the use of the last template parameter with default argument void. Due to the way the matching of partial class template specializations works (see, e.g., this answer), the specialization will only be picked if Slot<T> is a valid type. Note that above solution requires C++17. If you have to stay within C++14 (which you probably don't, given that your own example relies on C++17), you can, e.g., provide your own implementation of void_t (as explained here):
template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;
I am trying to tag-dispatch into a function with a reversed copy of a boost::mpl::vector:
using InitOrder = boost::mpl::vector<
struct Foo,
struct Bar,
struct Baz
>;
template <class... Stuff>
void initialize(boost::mpl::vector<Stuff...>) {
// Initialize in-order
}
template <class... Stuff>
void destroy(boost::mpl::vector<Stuff...>) {
// Exit in-order
}
void initializeAll() {
initialize(InitOrder{});
}
void destroyAll() {
destroy(typename boost::mpl::reverse<InitOrder>::type{});
}
Coliru demo
As you can see, the goal is to have two processes in initialize and destroy that have access to the Stuff pack. However, as answered here, boost::mpl::reverse<InitOrder>::type is actually not a boost::mpl::vector, and the dispatching fails:
main.cpp:27:2: error: no matching function for call to 'destroy'
destroy(typename boost::mpl::reverse::type{});
^~~~~~~
main.cpp:18:6: note: candidate template ignored: could not match 'vector' against 'v_item'
void destroy(boost::mpl::vector) {
^
How can I operate on a type list in both directions easily?
Is Boost.MPL inherently incompatible with variadic templates?
I can ditch Boost.MPL if needed, provided the alternative is standard or Boost. I'm using MSVC 14.1.
Is Boost.MPL inherently incompatible with variadic templates?
Basically. MPL predates C++11, so to use MPL, you need to use their algorithms - so their Sequence concept with their Iterators, etc. There's almost certainly a really short, clever way to do this, but I can only ever find those out with guess and check.
At least, if all you need to do is reverse, this is straightforward to implement in C++11:
template <typename...> struct typelist { };
template <typename TL, typeanme R>
struct reverse_impl;
template <typename T, typename... Ts, typename... Us>
struct reverse_impl<typelist<T, Ts...>, typelist<Us...>>
: reverse_impl<typelist<Ts...>, typelist<Us..., T>>
{ };
template <typename... Us>
struct reverse_impl<typelist<>, typelist<Us...>>
{
using type = typelist<Us...>;
};
template <typename TL>
using reverse = typename reverse_impl<TL, typelist<>>::type;
So given:
using InitOrder = typelist<struct Foo, struct Bar, struct Baz>;
Then reverse<InitOrder> would be typelist<struct Baz, struct Bar, struct Foo>, and so would be usable in the way you'd want.
Consider the following:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
using B = A<MyT>; // does not compile
int main() {
return 0;
}
When MyT is used as a default argument of A, the compiler (g++ 5.4.0) is happy. However, when it is used to instantiate A, the story is different:
temp.cpp:19:16: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class TT> struct A’
using B = A<MyT>;
^
temp.cpp:19:16: note: expected a template of type ‘template<class> class TT’, got ‘template<class ...> struct MyT’
I can fix it by introducing an alias:
template <class T>
using MyTT = MyT<T>;
using B = A<MyTT>; // fine
The question: what is the reason for the error and is there a solution without introducing an alias?
EDIT Please note that A is declared to have a template template parameter as shown and that is not given for change.
You cannot do that and you cannot use such a type as a default parameter. The fact that it seems to be accepted as long as you don't rely on it doesn't mean that the default parameter is a valid one.
Consider the following code that explicitly uses the default type:
template <class...>
struct MyT;
template <class T>
struct MyT<T> {};
template <template <class> class TT = MyT> struct A {}; // fine
int main() {
A<> a;
return 0;
}
The error is quite clear:
template template argument has different template parameters than its corresponding template template parameter
Partial specializations are not taken in account in this case, thus the two declarations differ.
You should either declare A as:
template <template <class...> class TT = MyT> struct A;
Or declare somewhere a type that is constrained to a single argument, as an example by means of an using declaration as you did.
First, the default argument doesn't work either.
Second, template template arguements are a strange beast. It would make sense if a template template argument would take anything that could be instantiated with the signature described in the template template argument.
That is not how it works.
Instead it works the other way around.
template<template<class...>class Z> struct foo {};
template<template<class >class Z> struct bar {};
template<class...>struct a{};
template<class >struct b{};
foo will accept a or b.
bar will accept only b.
The correct response to this, once you understand it, is "what the hell?". If you aren't responding "what the hell" back up and see if you can understand it. This basically works backwards from typical typing for arguements in C++; it behaves more like a return type than an argument. (Learn the terms contravariance and covariance if you want to see some of the language that lets you talk about this directly)
This is quite non-intuitive, and why it works this way exactly would involve tracking down the pre-history of C++.
But, as a benefit, a template<class...>class argument is in effect an "any template that only takes type parameters". I find this highly useful.
As a downside, template<class>class arguements are almost completely useless.
Tl;dr: make your template<template parameters be template<template<class...>class, and metaprogram only with templates that only take types. If you have a template that takes values, write a type wrapper that replaces a requirement for a std::size_t X with a std::integral_constant< std::size_t, X >.
Forgetting for a moment the question of "Why would you do this?",
the first version would work if you hadn't done any template specialization.
template <class T>
struct MyT { };
template <template <class> class TT = MyT> struct A
{};
using B = A<MyT>;
With template specialization, the compiler must determine the best match, but since you haven't ever actually provided any template arguments it's ambiguous.
When you introduce MyTT you are using a single template argument, and the compiler is smart enough to see that you have a specialization when there is only one arg:
template <class T>
using MyTT = MyT<T>;
It chooses the specialization instead of the variadic version in this case.
But now we circle back to the grand question... why? Unless within A you're always instantiating MyT with a specific class, it's pointless to use A at all:
template<template<class> class TT = MyT> struct A
{
// use an instance of TT??
TT<int> myInstance; // forced to choose `int`
};
I would like to split your question into 2 parts.
A) Consider the template of your structure is simpler
template <class T>
struct TestStruct {
};
template <
template <class>
class TT = TestStruct
>
struct A
{
int a; // sorry to modify this. This help to show how it works
};
int main() {
A< TestStruct > b;
b.a; // it works!
return 0;
}
It works because of the template class TT only accept the template with < class... > template. The specializated class is not count on this ( because the underlying of it is still template < class ... > )
B) even you update your struct A to the template< class... > one, you still have one more problem. What is the template argument of TT? Please see the example below
template <class...>
struct MyT;
template <class T>
struct MyT<T> {
int a;
};
template <
template <class...>
class TT = MyT
// may be you need to add some more typename here, such as
// typename T1, ... , and then TT<T1> a;
>
struct A
{
TT<int> a;
// Here ! TT is a template only, do not have the template parameters!!!
};
int main() {
A< MyT > b;
b.a; // it works!!
return 0;
}
But, if you really cannot update the signature of those definitions, you can do a proxy class
template< class T >
struct Proxy : MyT<T>
{
};
Consider the following structs:
//Implementations provided elsewhere
struct A { A(int i, double d, std::string s); /* ... */ };
struct B { B(double d1, double d2); /* ... */ };
I have two conversion classes whose template signatures look like:
TupleAs< A, int, double, std::string > via1 { ... };
ArrayAs< B, double, 2 > via2 { ... };
Predictably, TupleAs converts a triplet of int,double, and std::string values into an object of type A. Similarly, ArrayAs converts a pair of two double values into an object of type B. (And yes, there are reasons why I cannot call the A and B constructors directly.)
Improving the syntax
I would like to change the syntax so I can do the following:
TupleAs< A(int,double,std::string) > via1 { ... };
ArrayAs< B(double,2) > via2 { ... };
which, I think, is more descriptive of a conversion process. The TupleAs template declaration and corresponding partial specialization would look like this:
template <typename T> struct TupleAs;
template <typename T, typename ... Args>
struct TupleAs<T(Args...)> { ... };
Compiler errors
However, if I try to do something similar with the ArrayAs version:
template <typename T> struct ArrayAs;
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
I get the following errors in clang (3.6) when trying to instantiate it (ArrayAs< B(double,2)> test;):
typeAs.cpp:14:22: error: unknown type name 'N'
struct ArrayAs<T(U,N)>{
^
typeAs.cpp:14:10: warning: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
struct ArrayAs<T(U,N)>{
^~~~~~~~~~~~~~~
typeAs.cpp:13:45: note: non-deducible template parameter 'N'
template<typename T, typename U, unsigned N>
^
The gcc error diagnostic is a little different, but I won't post it here.
I admit that my templating skills should be better than they are, and I also concede that an analogous std::function<B(double,2)> declaration clearly is nonsense. But can someone tell me why the particular syntax I'm trying to achieve is not allowed? I looked through the C++14 standard and had trouble finding the relevant portion, and I'm having trouble interpreting the clang diagnostic message.
When you specialize TupleAs:
template <typename T, typename ... Args>
struct TupleAs<T(Args...)>
You are basically overloading the notation for a function. You are specializing on a function that takes Args... and returns a T. That is a type. You may not be using that function as a function, or really ever think about it as being a type, but that is what it is.
On the other hand, here:
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
There is no such thing as a function that takes N. It could take unsigned, but it can't take a value. There is just no such reasonable thing. From your example, B(double, 2) simply does not make sense. At best, you could write something that would allow:
template <unsigned N> using size_ = std::integral_constant<size_t, N>;
ArrayAs< B(double,size_<2>) >
Or even:
ArrayAs< B(std::array<double, 2>) >
since now we're back to using types everywhere. Whether you prefer that or not is personal preference.
The key here is that types are first-class citizens when it comes to all things template metaprogramming, and values should be avoided where possible.
template <typename T> struct ArrayAs;
template <typename T, typename U, std::size_t N>
struct ArrayAs<T(std::array<U,N>)> { ... };
works, as would:
template<class T>
struct to_array;
template<class T, size_t N>
struct to_array< T[N] > { using type = std::array<T, N>; };
template<class T>
using arr = typename to_array<T>::type;
then:
ArrayAs< Bob( arr<int[3]> ) > some_var;
live example.
Sadly, directly using ArrayAs< Bob( int[3] ) > doesn't work due to how arrays in function types decay to pointers.
I'm just starting learning C++11 and I never saw this syntax in the list of new features:
template <template <typename> class F>
struct fun;
what is it and how does it work?
Note: What you are looking at is an "old" feature, and has been there since long before c++11.
template <template <typename> class F> struct Obj;
In the above Obj is a template only accepting a template-parameter which is also a template[1]; this is most often referred to as a template-template parameter [2].
1) in this specific example it will only accept a template that takes one type-parameter.2) Link to SO question: Template Template Parameters
Imagine that you'd like to have a wrapper around some class template; you don't care which class template this is as long as you can specify a template argument for it.
If so, you can use a template-template parameter as in the below example:
template<template<typename T> class TemplateType>
struct Obj {
TemplateType< int> m1;
TemplateType<float> m2;
};
template<typename T>
struct SomeTemplate { /* ... */ };
Obj<SomeTemplate> foo;
In the above, foo will be a Obj<SomeTemplate> having two members:
SomeTemplate< int> m1
SomeTemplate<float> m2
This should works in C++98 as well. This is a template as an argument from a template. I mean a template class will expected as the argument for F.
Maybe this page will help you: http://www.cprogramming.com/tutorial/templates.html