I have a problem that Curiously Recurring Templates could help quite nicely, but I cant even get past a simple test.
template<typename T, int _size, typename OutterT>
class Foo {
};
template<typename T>
class Bar : public Foo<T, 2, Bar> {};
//typedef Bar<float> Vec2f;
int main()
{
return 0;
}
This results in the error
foo.cpp:7: error: type/value mismatch at argument 3 in template parameter list for ‘template<class T, int _size, class OuterT> class Foo’
foo.cpp:7: error: expected a type, got ‘Bar’
What am I missing.
compiled with g++ 4.2.1
template<typename T, int _size, typename OutterT>
class Foo {
};
template<typename T>
class Bar : public Foo<T, 2, Bar<T> > {};
// ^^^
Bar<float> x;
Since Bar is a template, you must provide the template argument to instantiate it into a class.
Related
Consider the following example:
template< class A, int B, class C>
struct Obj {
A a_obj;
static constexpr int b_value = B;
C c_obj;
};
template< template<class... > class ... Templates >
struct Foo;
template<>
struct Foo<Obj> {
Obj<void*, 5, float> obj;
};
int main() {
Foo<Obj> foo;
};
This is failing on me (g++ 7.2, with -std=c++17 with the following errors:
templ.cpp:16:15: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class ...> class ... Templates> struct Foo’
16 | struct Foo<Obj> {
| ^
templ.cpp:16:15: note: expected a template of type ‘template<class ...> class ... Templates’, got ‘template<class A, int B, class C> struct Obj’
templ.cpp: In function ‘int main()’:
templ.cpp:23:8: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class ...> class ... Templates> struct Foo’
23 | Foo<Obj> foo;
| ^
templ.cpp:23:8: note: expected a template of type ‘template<class ...> class ... Templates’, got ‘template<class A, int B, class C> struct Obj’
It seems that it is not getting matched, although it doesn't look like it thinks the template<class ...> class ... Templates is a syntax error, hence the parameter-parameter pack is parsing
Is this type of declaration (with some types, a constant value, then more types, or perhaps constant values at the end) unmatchable with variadic template template pack syntax? or perhaps I'm not using the syntax right
Edit
I modified the version to avoid non-types in declarations, but the problem persists:
template< template <class, class> class B, class A, class C>
struct Obj {
A a_obj;
//static constexpr int b_value = B;
B< C, A > b_obj;
C c_obj;
};
template< template<typename... > typename ... Templates >
struct Foo;
template<class A, class V>
struct Bar {
A a_obj;
//static constexpr int value = V;
V obj;
};
template<>
struct Foo<Obj> {
Obj<Bar, void*, float> obj;
};
int main() {
Foo<Obj> foo;
};
So it seems that is not that just non-types and types cannot be matches on a variadic pack, but any mixture of types and templates
I also tried adding an additional variadic pack:
template< template<typename... > typename ... Templates, class ... Types >
struct Foo;
But then I get:
error: parameter pack ‘template<class ...> class ... Templates’ must be at the end of the template parameter list
12 | template< template<typename... > typename ... Templates, class ... Types >
int B is a non-type template parameter. You have to declare Templates as template<class, auto, class> class if you want it to work with that particular class template, or redefine Obj to take a std::integral_constant to pass a value encapsulated in a type:
template<class A, class B, class C>
struct Obj {
A a_obj;
static constexpr int b_value = B::value;
C c_obj;
};
template<template<class...> class... Templates>
struct Foo;
template<>
struct Foo<Obj> {
Obj<void*, std::integral_constant<int, 5>, float> obj;
};
int main() {
Foo<Obj> foo;
}
Try it on godbolt.org.
I'm trying to mix-in an operator [] with a class. My problem is I've partially specialized the class, and the compiler doesn't like me not specifying the template parameters to the derived class:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
struct mixin {
template <typename U>
void operator[](U u) {
cout << u;
}
};
template <typename T, typename = void>
struct derived : mixin<derived> {};
template <typename T>
struct derived<T,
typename enable_if<
is_same<T, int>{}
>::type> : mixin<derived> {};
int main() {
derived<int> d;
d[3.14];
}
With clang this gives:
test.cc:16:24: error: use of class template 'derived' requires template arguments
struct derived : mixin<derived> {};
^~~~~~~
test.cc:16:8: note: template is declared here
struct derived : mixin<derived> {};
^
test.cc:23:22: error: use of class template 'derived' requires template arguments
>::type> : mixin<derived> {};
^~~~~~~
test.cc:16:8: note: template is declared here
struct derived : mixin<derived> {};
^
gcc is even less helpful:
test.cc:16:31: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct mixin’
struct derived : mixin<derived> {};
^
test.cc:16:31: note: expected a type, got ‘derived’
test.cc:23:29: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct mixin’
>::type> : mixin<derived> {};
^
test.cc:23:29: note: expected a type, got ‘derived’
test.cc: In function ‘int main()’:
Is my only option to re-specify the template parameters inside of the mixin clause?
Well, try this:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
struct mixin {
template <typename U>
void operator[](U u) {
cout << u;
}
};
template <typename T, typename = void>
struct derived : mixin<derived<T>> {};
template <typename T>
struct derived<T,
typename enable_if<
is_same<T, int>::value
>::type> : mixin<derived<T>> {};
int main() {
derived<int> d;
d[3.14];
}
It does work...
What I changed:
Using is_same<foo,bar>::value, not is_same<foo,bar>{} edit: Hmm, it seems you don't need to change that after all. Neat!
Not trying to get the compiler to deduce the template parameter for derived when using mixin<derived>. You were being way too optimistic there...
With the code below I've got compiler error:
type/value mismatch at argument 1 in template parameter list for 'template<class _Tp> class std::shared_ptr'
std::shared_ptr<T> shared_pointer;
^
../test/main.cpp:16:22: note: expected a type, got 'T'
Can't figure out why T is not properly deduced for shared_pointer?
template<typename K>
class Bar{
K k;
};
template<template<typename> class T>
class Foo{
public:
std::shared_ptr<T> shared_pointer;
};
int main(void)
{
Foo<Bar<std::string>> foo;
}
Update:
Another example:
template<typename TObject, template<TObject> class TBuffer>
class BaseGrabber {
public:
virtual void run(std::shared_ptr<TBuffer>){};
};
I want to force compiler error when someone write something like
BaseGrabber<int, Bar<long>> grabber;
so Bar never specialized with type that differs from first BaseGrabber template parameter.
Question 1:
[I] can't figure out why T is not properly deduced for shared_pointer?
template<template<typename> class T>
class Foo{
public:
std::shared_ptr<T> shared_pointer;
};
Answer: T cannot be deduced for shared_ptr because T is a templated type, and you're not giving it any template arguments. Simply reduce it to class T and it will work:
template<class T>
class Foo{
public:
std::shared_ptr<T> shared_pointer;
};
Question 2:
I want to force compiler error when someone write something like:
BaseGrabber<int, Bar<long>> grabber;
Answer:
We shall write an empty primary specialization for BaseGrabber, and then specialize it for when the second argument uses the same template argument type as the first argument:
template<class T, class U>
class BaseGrabber{
static_assert(sizeof(T) == 0, "Template argument is not correct");
};
template<class T, template<class> class U>
class BaseGrabber<T, U<T>> {
public:
virtual void run(std::shared_ptr<T>){};
}
Test it like so:
int main()
{
Foo<Bar<std::string>> foo;
//BaseGrabber<int, Bar<long>> grabber; // compiler error
BaseGrabber<int, Bar<int>> grabber;
}
Live Demo
I have written the following earth-shattering application:
class SomeA { }; class SomeB { }; class SomeC { };
template <typename A, typename B, typename... Cs>
class Foo {
public:
template <typename U> static void bar();
};
template <typename U>
void Foo<SomeA, SomeB, SomeC>::bar() { };
int main() { return 0; }
When I compile this (gcc 4.9.3 with -std=c++11), I get the following error:
a.cpp:10:36: error: ambiguating new declaration of ‘static void Foo<SomeA, SomeB, SomeC>::bar()’
void Foo<SomeA, SomeB, SomeC>::bar() { };
^
a.cpp:6:36: note: old declaration ‘static void Foo<A, B, Cs>::bar() [with U = U; A = SomeA; B = SomeB; Cs = {SomeC}]’
template <typename U> static void bar();
^
Why is this an "ambiguating declaration", and how else can I implement bar for all Us but for a specific instantiation of Foo?
With clang 3.6.2, I get the error:
a.cpp:9:1: error: template parameter list matching the non-templated nested type 'Foo<SomeA, SomeB, SomeC>' should be empty ('template<>')
template <typename U>
^ ~~~~~~~~~~~~
I don't really get this either. How am I supposed to template over U if clang wants an empty parameter list?
No idea what ambiguating new declaration means, but you're specializing the enclosing class template Foo, so you need to indicate that with an empty template parameter list
template <>
template <typename U>
void Foo<SomeA, SomeB, SomeC>::bar() { }
Live demo
I have a template class Foo that takes two (or more) template arguments. I want to use its type in a separate class Bar. See the following simple example, which compiles without error:
template <typename T, typename U> class Foo { };
template <typename T, typename U> class Bar { };
int main()
{
Bar<int, char> bar; // quick example -- int & char could be any 2 types
return 0;
}
The above is somewhat tedious, especially if Foo takes many template arguments and the programmer has to retype them all. I would like to have something like the following instead, but it does not compile:
template <typename T, typename U> class Foo { };
template <typename T, typename U> class Bar; // base
template <typename T, typename U> class Bar< Foo<T, U> > { }; // specialization
int main()
{
typedef Foo<int, char> FooType;
Bar<FooType> bar;
return 0;
}
test.cpp:3:60: error: wrong number of template arguments (1, should be 2)
test.cpp:2:45: error: provided for ‘template class Bar’
test.cpp: In function ‘int main()’:
test.cpp:7:18: error: wrong number of template arguments (1, should be 2)
test.cpp:2:45: error: provided for ‘template class Bar’
test.cpp:7:23: error: invalid type in declaration before ‘;’ token
I am especially perplexed because this partial specialization idiom works fine for a single template argument; see the question titled: total class specialization for a template
Edit I realized that, at least for my purposes, I could get around this using C++11 variadic templates as follows. I still want to know why the second example doesn't work, though.
template <typename... FooTypes> class Bar;
template <typename... FooTypes> class Bar< Foo<FooTypes...> > { };
Your class template Bar<T, U> takes two template arguments, but your specialization is only given one:
template <typename T, typename U> class Bar<Foo<T, U> > {};
Did you mean to have Bar take just one template argument and specialize it correspondingly?
template <typename T> class Bar;
template <typename T, typename U> class Bar<Foo<T, U> > {};
Note that a specialization can depend on a different number of template parameters but the specialization needs to get the same number of arguments. It also works the other way around: a full specialization can have no template parameter:
template <> class Bar<int> {};
I'm a little confused about what you're trying to do in this line:
template <typename T, typename U> class Bar< Foo<T, U> > { }; // specialization
You're stating that the template requires two types, T and U, as type parameters. Foo is itself only one type though, the type created by instantiating the Foo template with those two arguments.
I see that you're expecting it to pick up and determine the T and U since you used them in both places, but that doesn't circumvent the fact that you only provided one type argument for a two type template specialization.