I have the following nested template
class A {
template <typename T> class B {
template <typename U> void foo(U arg);
};
};
I am trying to define the nested template like so:
template <typename T, typename U> void
A::B<T>::foo(U arg) {...}
But am getting declaration is incompatible with function template error. What's the legal syntax to do so?
You need to separate the template declarations:
template <typename T>
template <typename U>
void
A::B<T>::foo(U arg) { … }
Related
I'm learning about template specializations and I wrote an example to better understand how it all works.
I'm reading C++ template complete guide.
The example is a bit contrived, so be advised it's just for learning purposes:
I define the primary template:
#include <iostream>
#define PRINT(msg) std::cout << (msg)
#define PRINTLN(msg) PRINT(msg) << std::endl;
/***** primary template ****/
template <typename T1>
class A
{
public:
template <typename T2>
struct B;
};
template <typename T1>
template <class T2>
struct A<T1>::B
{
template <typename T3>
struct C;
};
template <typename T1>
template <typename T2>
template <typename T3>
struct A<T1>::B<T2>::C
{
void MemberFunction();
template <typename F>
void MemberFunctionTemplate();
};
template <typename T1>
template <typename T2>
template <typename T3>
void A<T1>::B<T2>::C<T3>::MemberFunction()
{
PRINTLN("1");
}
template <typename T1>
template <typename T2>
template <typename T3>
template <typename F>
void A<T1>::B<T2>::C<T3>::MemberFunctionTemplate()
{
PRINTLN("2");
}
then I fully specialize the nested struct C:
/**** explicit (full) class template specialization for struct C ****/
// template <> for each enclosing class template
template <>
template <>
template <>
struct A<float>::B<int>::C<int>
{
template <typename T>
void MemberFunctionTemplate();
void MemberFunction(); // definition in specialization.cpp
struct D;
};
// no template <>
template <typename T>
void A<float>::B<int>::C<int>::MemberFunctionTemplate()
{
PRINTLN("4");
}
// no template <>
struct A<float>::B<int>::C<int>::D // ERROR!
{
static void StaticMemberFunction();
};
since a full specialization is not a template anymore, I can define out of class members without the template <> prefix syntax. I put member function definitions in a cpp file (so I don't break the ODR), and I define my nested struct D inside the header file for the compiler to see.
But I get an error from the compiler when the struct D definition is first seen:
In file included from main.cpp:1:0:
specialization.hpp:94:34: error: too few template-parameter-lists
struct A<float>::B<int>::C<int>::D
^
In file included from specialization.cpp:1:0:
specialization.hpp:94:34: error: too few template-parameter-lists
struct A<float>::B<int>::C<int>::D
It doesn't make sense to me, since I'm defining the struct correctly out of its enclosing (specialized) class. I tried adding a template <> but of course it's wrong.
If I try to fully specialize class A and add a struct D (like I'm trying to do in full class template specialization of struct C), it all works. Why?
I have a template class that declares a friend function which itself has template parameters. The code looks like this:
template <class T>
class C;
template <class T, class U>
void func(C<T>& t);
template <class T>
class C
{
template <class U>
friend void func<T, U>(C<T>& t);
private:
template <class U>
void f()
{
}
};
template <class T, class U>
void func(C<T>& t)
{
t.f<U>();
}
But when I try to call func, I get a compilation error at the friend line:
'func': no matching overloaded function found
How can I make func<T, U> friend with C<T>?
The key issue is that the friend you declared, is not the same as the previous declaration you provided. The first expects two template parameters, but the second (friend) you defined to accept only one. Once that is resolved, everything works:
template <class T>
class C;
template <class U, class T>
void func(C<T>& t);
template <class T>
class C
{
template <class U, class TT>
friend void func(C<TT>& t);
private:
template <class U>
void f()
{
}
};
template <class U, class T>
void func(C<T>& t)
{
t.template f<U>();
}
int main() {
C<int> c;
func<bool>(c);
}
Watch it live.
Note I switched U and T up, because I assumed you may want T deduced and U explicitly specified.
I have the following struct and function
template <class T> struct C {};
template <template <class S> class T, class U> void f() { T<U> tu; }
when templating f() with C I do not get an error, when templating it with say std::vector I do.
int main() {
f<C, int>();
}
yields no errors
int main() {
f<std::vector, int>();
}
yields
error: no matching function for call to 'f'
f<std::vector, int>();
^~~~~~~~~~~~~~~~~~~~~~~~
note: candidate template ignored: invalid explicitly-specified argument for template parameter 'T'
template <template <class S> class T, class U> void f() { T<U> tu; }
What is the difference between C and std::vector here?
That's because vector has two template parameters, not one (T and Allocator).
You can either change your f template to accept two template parameters (or a variadic pack):
template <template <class...> class T, class U> void f() { T<U> tu; }
or you can alias vector to a 1-parameter template:
template<typename T>
using vec = std::vector<T>;
difference is that vector has two template parameters, not one. To fix this you may use
template <template <class... S> class T, class U> void f() { T<U> tu; }
For structs
<template typename T>
struct Foo
{
...
}
<template typename T>
struct Boo
{
...
}
I want to create function that i will call like
DoSomething<Boo<int>>(x);
DoSomething<Foo<float>>(x);
I tried something like this
<template typename T>
<template typename U>
void DoSomething(T<U>& x)
but it doesn't compile. How do I make template for this kind of function?
Thanks
just do:
template <typename T>
struct Foo
{
};
template <typename T>
struct Boo
{
};
template <typename T>
void DoSomething(T& x) // One parameter is enough, compiler will deduce types automatically
{
}
Boo<int> x;
Foo<float> y;
DoSomething(x); // compiler will generate void DoSomething(Boo<int>& x)
DoSomething(y); // compiler will generate void DoSomething(Foo<float>& x)
Your template declaration is wrong,
<template typename T> // invalid syntax
should be:
template <typename T>
You need to use template template parameter if you want to specify both types:
template <template<typename> class T, typename U>
void DoSomething(T<U>& x)
But depending on what you want to achieve, if you don't need to have both types in your function, simply using a single template parameter should work:
template <typename Y>
void DoSomething(T& x)
<template typename T>
void DoSomething(T& x)
{
// do something
}
You have two choices. For the sake of the examples, consider your Foo template struct and this declaration:
Foo<double> v;
Your first choice is
template <typename T>
void DoSomething1(T& x) { /* ... */ }
// ...
DoSomething1(v);
I strongly believe this is what you need.
However, it might not be the case. Perhaps, you really need to call the function on a type of the form T<U> where T is a template class and U is a type. For instance you might want to instantiate T with an int (that is, create T<int> y;) inside the function's body. Then, your second choice is
template <template <typename> class T, typename U>
void DoSomething2(T<U>& x) { T<int> y; /* ... */ }
// ...
DoSomething2(v);
Unfortunately, this might not yet be enough! If you try,
std::vector<double> w;
// ...
DoSomething2(w);
The last line fails to compile. The reason is that std::vector is a template class that take two type parameters and DoSomething2 expects a template class that takes just one. (Of course one can instantiate std::vector with just one argument because the second one has a default value.) The solution is using a C++11 variadic template template parameter:
template <template <typename, typename...> class T, typename U>
void DoSomething3(T<U>&) { T<int> y; /* ... */ }
// ...
DoSomething3(v);
DoSomething3(w);
Here is my somewhat odd code:
template <typename T&>
class A {
public:
void b(typename std::enable_if<!std::is_pointer<T>::value, T>;::type o) {}
void b(typename std::enable_if<std::is_pointer<T>::value, T>;::type o) {}
};
template <typename T>
void b(typename std::enable_if<!std::is_pointer<T>::value, T>::type o) {}
template <typename T>
void b(typename std::enable_if<std::is_pointer<T>::value, T>::type o) {}
If I ifdef out the method b and call b<int *>(pi) where pi is int *, everything compiles.
If I ifdef out the function b (outside class) and call A<int *> a; a.b(pi), I get the following error:
error: no type named 'type' in 'std::__1::enable_if<false, int *>'
Why the inconsistency and how can I fix the problem so that I can use the methods in A?
The problem is, that SFINAE only works during overload resolution and only if the function itself is a template. In your method case, the whole class is a template, meaning that there is no substitution of the template parameter (remember: SFINAE == "Substitution Failure Is Not An Error").
At the point of instantiation, the method signatures look like this (nevermind the call to them):
void A<int*>::b(std::enable_if<false, int*>::type o) // error
void A<int*>::b(std::enable_if<true, int*>::type o)
To fix this, make the methods templates too:
template<class T>
class A{
public:
template<class U>
void b(U o, typename std::enable_if<!std::is_pointer<U>::value>::type* = 0){}
// same for the other version
};
On a side note, letting the template argument get deduced is the better way to use SFINAE, so you should modify the free functions to look like this:
template<class T>
void b(T o, typename std::enable_if<!std::is_pointer<T>::value>::type* = 0){}
// same for the other version
In C++11, you can even use the template parameters for SFINAE:
template<class T, EnableIf<std::is_pointer<T>> = {}>
void b(T o);
Utilizing an alias from the blog entry linked from here:
namespace detail{ enum class enabler{}; }
template<class Cond, class T = detail::enabler>
using EnableIf = typename std::enable_if<C::value, T>::type;
For the explanation, see Xeo's answer.
For the work-around: just add a dummy template parameter to the method
#include <utility>
#include <type_traits>
template <typename T>
class A {
public:
template <typename U = T>
void b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o);
template <typename U = T>
void b(typename std::enable_if<std::is_pointer<U>::value, U>::type o);
};
template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o) {}
template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<std::is_pointer<U>::value, U>::type o) {}
int main() {
A<int> a;
a.b(0);
}
Live Demo Here.
You are not using SFINAE correctly because the compiler can't deduce the argument for enable_if<...>::type and probably that's why it fails.
Correct declarations of free-standing functions would be:
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, void>::type b(T o);
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type b(T o);
In this particular case plain function overloading can be used as well:
template <typename T>
void b(T);
template <typename T>
void b(T*);