I having a problem trying to get template to work with an alias nested in one of its arguments. It works if I make an alias in the template itself and use that as an argument to another template. I would like to use it without doing this so that it can be passed down through inheritance to another template.
I think my problem has something to do with the compiler not knowing what the template arguments are and says the template argument is invalid, but I don't know if there is a way to correct this without using the extra alias.
template< template<typename>class T >
struct TemplateWrapper {
template<typename U>
using type = T<U>;
};
template<typename T>
struct TemplateTester{
template<typename U>
using type = typename T::template type<U>; //This works fine
TemplateWrapper<type> test; //This works fine
TemplateWrapper< typename T::template type > test2; //error: template argument 1 is invalid
};
I'm using MinGW with GCC 4.7.1.
Any help would be appreciated.
Related
I'm wondering if there is or will be a way in C++ which allows to typedef a template template argument similar to typedef a template argument.
The only way i know of at the moment is using an alias template
template<template<typename> typename T>
struct S {
template <typename U>
using TT = T<U>;
};
but that seems too repetitive.
Is there something like
typedef T TT;
or
typename T TT;
to achieve the same?
If not, would it even make sense or am i missing something obvious?
EDIT:
Since this has been marked as possible duplicate i'm trying to rephrase what i'm after.
A typedef creates an alias for one complete type.
An alias template creates an alias for a family of types.
I'm wondering if there is or will be something that creates an alias to a incomplete thing like a template template parameter.
The duplicate question does neither answer whether there is or will be an alternative to the alias template nor if or if not such an alternative would make sense.
I am trying to use a template template parameter and my code will not complile.
template<class DataType, template<class T> class Container>
void foo(Container<DataType> test)
{
}
int main()
{
std::vector<int> testVec{1,2,3,4};
foo<int, std::vector>(testVec);
}
The error message is
"No matching function for call to 'foo'.
Candidate template ignored: invalid explicitly-specified argument for template parameter 'Container'"
Can someone help me out?
Suggestion: try with
// ...............................VVVVVVVVV
template<class DataType, template<class ...> class Container>
void foo(Container<DataType> test)
{
}
The problem is that std::vector accept two type template parameters; the second one with a default value.
If you write
// ...............................VVVVVVV
template<class DataType, template<class T> class Container>
you ask for a template-template parameter that accept a single type template parameter.
So you can solve asking two type template parameters
// ...............................VVVVVVVVVVVV
template<class DataType, template<class, class> class Container>
or, to be more flexible, a variadic list of type template parameters
// ...............................VVVVVVVVV
template<class DataType, template<class ...> class Container>
As pointed by HolyBlackCat (thanks) your code (so a template-template parameter asking for a single type template parameter) should fail before C++17 but should be accepted starting from C++17 (the matching rules are changed).
Unfortunately this works with g++ but not for clang++: the clang++ developer doesn't implement, by default, this new C++17 matching rule.
But HolyBlackCat report that also clang++ accept your code adding a special parameter: -frelaxed-template-template-args.
What I want is something like std::bind for functions but for templates.
Assume I have a template which needs a template template with a defined set of arguments.
Now I have another template which would work but which has more arguments, so I need to convert this complex template into a simpler one with bound arguments.
To do this I created a template which defines an alias template.
If I use this binding template with concrete types this works well. But if I instantiate the binding template with another template argument, gcc and clang assume that the alias is not a template template. I know it becomes a dependent name, but there is nothing like the typename disambiguator for templates.
With icc and msvc this works fine.
template<
template<typename> typename Template
>
class ATypeWhichNeedsATemplateTemplate
{
};
template<typename A, typename B>
class AComplexTemplate
{
};
template<
template<typename...> typename ATemplate
,typename... Args
>
class Binder {
public:
template<typename T>
using type = ATemplate<T, Args...>;
};
template<typename T>
class AClassWithBoundTemplate : public ATypeWhichNeedsATemplateTemplate<
Binder<AComplexTemplate, T>::type
>
{
};
see on godbolt
clang complains:
<source>:30:5: error: template argument for template template parameter must be a class template or type alias template
Binder<AComplexTemplate, T>::type
^
gcc says something similar:
<source>:31:1: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class Template> class ATypeWhichNeedsATemplateTemplate'
>
^
<source>:31:1: note: expected a class template, got 'Binder<AComplexTemplate, T>::type'
type is a dependent template name. You need to spell it like Binder<AComplexTemplate, T>::template type, i. e.:
template<typename T>
class AClassWithBoundTemplate : public ATypeWhichNeedsATemplateTemplate<
Binder<AComplexTemplate, T>::template type
>
{
};
Fixed godbolt example: https://godbolt.org/z/7nJtAU
You can have a "shorthand" for a class template from a namespace by only giving the name of the template. However if the class template is in a class, I have to create an alias template and write out all the template parameters and arguments - which is bad for maintainability:
namespace mynamespace {
template<template<class> class T>
class MyClass;
}
using mynamespace::MyClass; // OK, straight and simple
class MyOuterClass {
public:
template<template<class> class T>
class MyInnerClass;
};
// using MyInnerClass = MyOuterClass::MyInnerClass; // error: invalid use of template-name 'MyOuterClass::MyInnerClass' without an argument list
// template<typename... TArgs> // error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class T> class MyOuterClass::MyInnerClass'
// using MyInnerClass = MyOuterClass::MyInnerClass<TArgs...>;
template<template<class> class T> // OK, but copying the template parameter list is bad, there should be some "auto" mechanism...
using MyInnerClass = MyOuterClass::MyInnerClass<T>;
int main(){}
Run code
Can I have a "shorthand" for such a template in a simpler way?
No. There is no such way. To using statements which are used (no pun intended) to make the definition visible are actually different versions of the same keyword. One is a using declaration, and another is an alias for typedef. They work differently and provide for different (though some times similarly looking) results.
If MyOuterClass::MyInnerClass<> only had type template parameters, you could use the following variadic alias template:
template<typename... TArgs>
using MyInnerClass = MyOuterClass::MyInnerClass<TArgs...>;
However, you still have to provide the parameter pack TArgs.
Assuming C++17, if MyOuterClass::MyInnerClass<> only had non-type template parameters you could use the following variadic alias template:
template<auto... Val>
using MyInnerClass = MyOuterClass::MyInnerClass<Val...>;
This is a follow-up of another question. It refers to the same problem (I hope) but uses an entirely different example to illustrate it. The reason is that in the previous example only experimental GCC 4.9 failed with a compiler error. In this example, also Clang and GCC 4.8.1 fail in different ways: Clang produces an unexpected result and GCC 4.8.1 reports a different error message.
Answers to the previous question say more or less that the code is valid and the problem lies with the experimental version of GCC. But this result makes me a bit more sceptical. I have been troubled for months with problems that I suspect are related (or the same), and this is the first time I have a small concrete example to illustrate.
So, here is some code. First, some generic code that applies SFINAE to an arbitrary test as specified by a variadic template alias metafunction F:
#include <iostream>
using namespace std;
using _true = integral_constant <bool, true>;
using _false = integral_constant <bool, false>;
template <typename T> using pass = _true;
template <template <typename...> class F>
struct test
{
template <typename... A> static _false _(...);
template <typename... A> static pass <F <A...> > _(int);
};
template <template <typename...> class F, typename... A>
using sfinae = decltype(test <F>::template _<A...>(0));
Second, a specific test, checking if a given class has defined a type named type:
template <typename T> using type_of = typename T::type;
template <typename T> using has_type = sfinae <type_of, T>;
Finally, an example:
struct A { using type = double; };
int main()
{
cout << has_type <int>() << ", ";
cout << has_type <A>() << endl;
}
The expected result would be 0, 1. Clang says 0, 0. GCC 4.8.1 says
tst.cpp: In substitution of ‘template<class T> using type_of = typename T::type [with T = A ...]’:
tst.cpp:15:51: required from ‘struct test<type_of>’
tst.cpp:19:67: required by substitution of ‘template<template<class ...> class F, class ... A> using sfinae = decltype (test:: _<A ...>(0)) [with F = type_of; A = {T}]’
tst.cpp:24:58: required from here
tst.cpp:23:56: error: ‘A ...’ is not a class, struct, or union type
template <typename T> using type_of = typename T::type;
^
and GCC 4.9 says
tst.cpp:19:67: required by substitution of ‘template<template<class ...> class F, class ... A> using sfinae = decltype (test:: _<A ...>(0)) [with F = type_of; A = {T}]’
tst.cpp:24:58: required from here
tst.cpp:15:51: error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T> using type_of = typename T::type’
template <typename... A> static pass <F <A...> > _(int);
^
(line numbers may vary). So, everything fails, in different ways.
Now, here is a workaround. Metafunction car picks the first type fom a given pack, and then the test is redefined as type_of2, now being variadic:
template <typename... T> struct car_t;
template <typename... T> using car = type_of <car_t <T...> >;
template <typename T, typename... Tn>
struct car_t <T, Tn...> { using type = T; };
template <typename... T> using type_of2 = typename car <T...>::type;
template <typename T> using has_type2 = sfinae <type_of2, T>;
int main()
{
cout << has_type2 <int>() << ", ";
cout << has_type2 <A>() << endl;
}
Now all three compilers say 0, 1 as expected. It is interesting that for any version of GCC we have to remove has_type (even if we don't use it) and leave only has_type2; otherwise we have similar error.
To wrap up: I see the problem with one template expecting a variadic template-parameter of the form
template <typename...> class F
where we actually give as input a non-variadic template alias of the form
template <typename T> using alias = // ... anything including T or not
and finally invoke F as if it was variadic:
F <A...>
Opinions so far say this is valid, but now it seems three compilers disagree. So the question is again: is it valid?
To me it matters because I have dozens of files of existing code based on the assumption that this is valid, and now I need a redesign anyway (since there are practical problems with these compilers) but the exact redesign will depend on the answer.
This does not answer the question whether the code above is valid, but is a quite pretty workaround that I have found by experimenting shortly after asking the question, and I think is useful to share.
All that is needed are the following definitions:
template <template <typename...> class F>
struct temp { };
template <typename... A, template <typename...> class F>
F <A...> subs_fun(temp <F>);
template <template <typename...> class F, typename... A>
using subs = decltype(subs_fun <A...>(temp <F>()));
then, wherever F <A...> would be problematic, replace it with subs <F, A...>. That's it. I cannot explain why, but it has worked in all cases so far.
For instance, in the SFINAE example of the question, just replace line
template <typename... A> static pass <F <A...> > _(int);
by
template <typename... A> static pass <subs <F, A...> > _(int);
This is a change at one point only, all remaining code stays the same. You don't need to redefine or wrap every template metafunction that with be used as F. Here's a live example.
If F <A...> is indeed valid and compilers support it eventually, it is again easy to switch back because changes are minimal.
I find this important because it allows specifying a SFINAE test in just two lines
template <typename T> using type_of = typename T::type;
template <typename T> using has_type = sfinae <type_of, T>;
and is completely generic. Typically, each such test needs at least 10 lines of code and implementations of <type_traits> are full of such code. In some cases such code blocks are defined as macros. With this solution, templates can do the job and macros are not needed.
I think the situation is pretty well standardized; C++11 14.3.3/1 says:
A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.