I have a class as shown below:
template <class T>
class outer {
public:
typedef T TType;
std::vector <TType> v;
int f1 (TType t) {cout << "t= " << t << endl;};
class inner {
public:
inner& operator=(const inner &in) {return *this;}
void f2(const inner &in) {cout << "in f2\n";}
};
inner read() {cout << "in read\n";return inner();}
};
Outer has to have nested inner. I have to create a Base class for outer (We are going backwards here !!). I should be able to derive outer1 from the Base. Existing clients of outer should work without changing anything. outer should just add code to derive from the base class.
My solution to this is:
template <typename T>
class outer_iface {
public:
typedef T TType;
std::vector <TType> v;
virtual int f1(TType t) {cout << "bt= " << t << endl;};
template <typename U>
class inner_iface {
public:
using value_type = U;
inner_iface& operator=(const inner_iface &in)
{
return static_cast <U*> (this)->operator=(in);
}
void f2(const inner_iface &in)
{
return static_cast <U*> (this)->f2(in);
}
}; //inner_biface
/*template <typename U>
typename inner_iface <U>::value_type read()
{
return static_cast <U*> (this)->read();
}*/
};
template <typename T>
class outer : public outer_iface <T> {
public:
typedef T TType;
std::vector <TType> v;
int f1 (TType t) {cout << "t= " << t << endl;};
class inner : public outer_iface <T> :: template inner_iface <inner> {
public:
inner& operator=(const inner &in) {return *this;}
void f2(const inner &in) {cout << "in f2\n";}
};
inner read() {cout << "in read\n";return inner();}
};
This compiles and builds. But, I have 2 questions:
is my declaration/definition of read correct in outer_iface?
how can I instantiate an outer_iface, with say int type, and call read ?
I tried from main():
outer_iface<int> oi;
oi.read();
clang gave errors:
g++ -g --std=c++11 test7.cpp
test7.cpp: In function ‘int main()’:
test7.cpp:62:11: error: no matching function for call to
‘outer_iface<int>::read()’oi.read();
^
test7.cpp:62:11: note: candidate is:
test7.cpp:28:40: note: template<class U> typename
outer_iface<T>::inner_iface<U>::value_type outer_iface<T>::read()
[with U = U; T = int]
typename inner_iface <U>::value_type read()
^
test7.cpp:28:40: note: template argument deduction/substitution failed:
test7.cpp:62:11: note: couldn't deduce template parameter ‘U’
oi.read();
So, obviously I don't have it right. How can I fix inner_face::read ?
Any help/insight is appreciated.
thanks
sdp
It seems that you want something like:
template <typename T>
class outer_iface {
public:
// ...
typename T::inner read()
{
// std::cout << "in read\n"; return typename T::inner();
return static_cast<T*>(this)->read();
}
};
Related
I have a template class and a member function print() to print the data.
template<typename T>
class A
{
public:
T data;
void print(void)
{
std::cout << data << std::endl;
}
// other functions ...
};
Then, I want to either print scalar data or vector data, so I give a specialized definition and get a compiler error.
template<typename T>
void A<std::vector<T>>::print(void) // template argument list error
{
for (const auto& d : data)
{
std::cout << d << std::endl;
}
}
Question: Why does this member function specialization get an error? What is the correct way to define a print function for a vector?
Solution 1: I have tested the following definition.
template<typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print(void) { // OK
// ...
}
}
This one worked, but I have to copy the other member functions into this specialized class.
EDIT:
Solution 2: To prevent copy all the other member functions, I define a base class containing the common member functions and inherit from the base class:
template<typename T>
class Base
{
public:
T data;
// other functions ...
};
template<typename T>
class A : public Base<T>
{
public:
void print(void)
{
std::cout << this->data << std::endl;
}
};
template<typename T>
class A<std::vector<T>> : public Base<std::vector<T>>
{
public:
void print(void)
{
for (const auto& d : this->data)
{
std::cout << d << std::endl;
}
}
};
This solution works well. Are there some better or more conventional solutions?
Why does this member function specialization get error?
When you instantiate the template class A for example A<std::vector<int>>, the template parameter T is equal to std::vector<int>, not std::vector<T>, and this a specialization case of the function. Unfortunately this can not be done with member functions as mentioned in the comments.
Are there some better solutions?
Yes; In c++17 you could use if constexpr with a trait to check the std::vector, like this.
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
void print() const /* noexcept */
{
if constexpr (is_std_vector<T>::value) // when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else // for types other than `std::vector<>`
{
std::cout << mData << std::endl;
}
}
};
(See Live Online)
This way you keep only one template class and the print() will instantiate the appropriate part according to the template type T at compile time.
If you don not have access to C++17, other option is to SFINAE the members(Since c++11).
#include <type_traits> // std::false_type, std::true_type, std::enbale_if
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
template<typename Type = T> // when T == `std::vector<>`
auto print() const -> typename std::enable_if<is_std_vector<Type>::value>::type
{
for (const auto element : mData)
std::cout << element << "\n";
}
template<typename Type = T> // for types other than `std::vector<>`
auto print() const -> typename std::enable_if<!is_std_vector<Type>::value>::type
{
std::cout << mData << std::endl;
}
};
(See Live Online)
What if I have more other data types like self-define vector classes
or matrices? Do I have to define many is_xx_vector?
You can check the type is a specialization of the provided one like as follows. This way you can avoid providing many traits for each type. The is_specialization is basically inspired from this post
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// custom MyVector (An example)
template<typename T> struct MyVector {};
template<typename Test, template<typename...> class ClassType>
struct is_specialization final : std::false_type {};
template<template<typename...> class ClassType, typename... Args>
struct is_specialization<ClassType<Args...>, ClassType> final : std::true_type {};
And the print function could be in c++17:
void print() const /* noexcept */
{
if constexpr (is_specialization<T, std::vector>::value)// when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else if constexpr (is_specialization<T, ::MyVector>::value) // custom `MyVector`
{
std::cout << "MyVector\n";
}
else // for types other than `std::vector<>` and custom `MyVector`
{
std::cout << mData << std::endl;
}
}
(See Live Online)
You need to implement a template class that uses a vector as template parameter. This worked for me.
template<typename T>
class A
{
public:
T data;
void print(void) {
std::cout << "Data output" << std::endl;
}
// other functions ...
};
template <typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print() {
for (auto i : data) {
std::cout << "Vector output" << std::endl;
}
}
};
You could always use named tag dispatching to check if type provided by template user is vector.
A<std::vector<T>> notation won't work as you both try to take into account that T is type and vector of types which is contradicting with itself.
Below is code I used named tag dispatching as solution to your problem:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template<typename T> struct is_vector : public std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type {};
template<typename T>
class A
{
public:
T data;
void print(std::true_type) {
for (auto& a : data) { std::cout << a << std::endl; }
}
void print(std::false_type) {
std::cout << data << std::endl;
}
void print() {
print(is_vector<T>{});
}
};
int main()
{
A<int> a;
a.data = 1;
a.print();
A<std::vector<int>> b;
b.data = { 1, 2 ,3 ,4 ,5 };
b.print();
return 0;
}
Succesfully compiled with https://www.onlinegdb.com/online_c++_compiler
Based on answer: Check at compile-time is a template type a vector
You can dispatch printing to another member function (static or not). For example:
template<typename T>
class A {
public:
T data;
void print() const {
print_impl(data);
}
private:
template<class S>
static void print_impl(const S& data) {
std::cout << data;
}
template<class S, class A>
static void print_impl(const std::vector<S, A>& data) {
for (const auto& d : data)
std::cout << d;
}
};
Let's consider a CRTP template class Print which is meant to print the derived class:
template <typename T>
struct Print {
auto print() const -> void;
auto self() const -> T const & {
return static_cast<T const &>(*this);
}
private:
Print() {}
~Print() {}
friend T;
};
Because I want to specialize print based on the derived class like we could do this with an override, I don't implement the method yet.
We can wrap an Integer and do so for example:
class Integer :
public Print<Integer>
{
public:
Integer(int i) : m_i(i) {}
private:
int m_i;
friend Print<Integer>;
};
template <>
auto Print<Integer>::print() const -> void {
std::cout << self().m_i << std::endl;
}
This works so far, now let's say I want to Print a generic version of a wrapper:
template <typename T>
class Wrapper :
public Print<Wrapper<T>>
{
public:
Wrapper(T value) : m_value(std::move(value)) {}
private:
T m_value;
friend Print<Wrapper<T>>;
};
If I specialize my print method with a specialization of the Wrapper it compile and works:
template <>
auto Print<Wrapper<int>>::print() const -> void
{
cout << self().m_value << endl;
}
But if I want to say "for all specializations of Wrapper, do that", it doesn't work:
template <typename T>
auto Print<Wrapper<T>>::print() const -> void
{
cout << self().m_value << endl;
}
If I run this over the following main function:
auto main(int, char**) -> int {
auto i = Integer{5};
i.print();
auto wrapper = Wrapper<int>{5};
wrapper.print();
return 0;
}
The compiler print:
50:42: error: invalid use of incomplete type 'struct Print<Wrapper<T> >'
6:8: error: declaration of 'struct Print<Wrapper<T> >'
Why ? How can I do that ? Is it even possible or do I have to make a complete specialization of my CRTP class ?
You can do this in a bit of a roundabout way so long as you're careful.
Live Demo
Your Print class will rely on yet another class PrintImpl to do the printing.
#include <type_traits>
template<class...>
struct always_false : std::false_type{};
template<class T>
struct PrintImpl
{
void operator()(const T&) const
{
static_assert(always_false<T>::value, "PrintImpl hasn't been specialized for T");
}
};
You'll partially specialize this PrintImpl for your Wrapper class:
template<class T>
struct PrintImpl<Wrapper<T>>
{
void operator()(const Wrapper<T>& _val) const
{
std::cout << _val.m_value;
}
};
And make sure that Wrapper declares this PrintImpl to be a friend:
friend struct PrintImpl<Wrapper<T>>;
The Print class creates an instance of PrintImpl and calls operator():
void print() const
{
PrintImpl<T>{}(self());
}
This works so long as your specializations are declared before you actually instantiate an instance of the Print class.
You can also fully specialize PrintImpl<T>::operator() for your Integer class without writing a class specialization:
class Integer :
public Print<Integer>
{
public:
Integer(int i) : m_i(i) {}
private:
int m_i;
friend PrintImpl<Integer>;
};
template <>
void PrintImpl<Integer>::operator()(const Integer& wrapper) const {
std::cout << wrapper.m_i << std::endl;
}
I don't know if this is possible, but I would like to understand better how this works.
Can a class implict convertsion operation be used to match a template parameter?
This is what I want to do.
#include <iostream>
template<typename T>
struct Value {
};
template<>
struct Value<int> {
static void printValue(int v) {
std::cout << v << std::endl;
}
};
struct Class1 {
int value;
};
/*
template<>
struct Value<Class1*> {
static void printValue(Class1* v) {
std::cout << v->value << std::endl;
}
};
*/
template<typename X>
struct ClassContainer {
ClassContainer(X *c) : _c(c) {}
operator X*() { return _c; }
X *_c;
};
template<typename X>
struct Value<ClassContainer<X>> {
static void printValue(ClassContainer<X> v) {
std::cout << static_cast<X*>(v)->value << std::endl;
}
};
template<typename X>
void doPrintValue(X v)
{
Value<X>::printValue(v);
}
int main(int argc, char *argv[])
{
doPrintValue(10);
Class1 *c = new Class1{ 20 };
//doPrintValue(c); // error C2039: 'printValue': is not a member of 'Value<X>'
ClassContainer<Class1> cc(c);
doPrintValue(cc);
std::cout << "PRESS ANY KEY TO CONTINUE";
std::cin.ignore();
}
ClassContainer has an implict conversion to X*. Is it possible to match ClassContainer passing only X*?
If you want the template class for pointers to behave like the template class for something else, just inherit:
template<typename T>
struct Value<T*> : Value<ClassContainer<T>> {};
It will inherit the public printValue function, which accepts a parameter that can be constructed from T*, and everything will be implicitly converted as expected.
See it all live here.
First, I've read over many other questions and couldn't find the solution. So before marking it a duplicate, please make sure duplicate answers the question.
I'm trying to specialize F::operator() for a class C2; however, C2 has a template parameter and I want F::operator() to behave the same for all C2's.
Compiler error:
error: invalid use of incomplete type ‘struct F<C2<T> >’
void F<C2<T>>::operator()()
Also, instead of Handle& h, I tried Handle* h and received the same error.
#include<iostream>
struct C1
{
void foo()
{
std::cout << "C1 called" << std::endl;
}
};
template<typename T>
struct C2
{
void bar();
};
template<>
void C2<int>::bar()
{
std::cout << "C2<int> called" << std::endl;
}
template<typename Handle>
struct F
{
F(Handle& h_) : h(h_) {}
void operator()();
Handle& h;
};
template<>
void F<C1>::operator()()
{
h.foo();
}
template<typename T>
void F<C2<T>>::operator()()
{
h.bar();
}
int main()
{
C1 c1;
F<C1> f_c1 (c1);
f_c1();
C2<int> c2;
F<C2<int>> f_c2 (c2);
f_c2();
}
There's no such thing like a partial specialization of a member function. You'd need to first partial-specialize the entire class:
template <typename T>
struct F<C2<T>>
{
void operator()();
};
template <typename T>
void F<C2<T>>::operator()() {}
Since this is a heavy-weight solution, alternatively, you can exploit tag-dispatching:
template <typename T> struct tag {};
template <typename Handle>
struct F
{
F(Handle& h_) : h(h_) {}
void operator()()
{
call(tag<Handle>{});
}
private:
void call(tag<C1>)
{
h.foo();
}
template <typename T>
void call(tag<C2<T>>)
{
h.bar();
}
Handle& h;
};
DEMO
Is it possible to hide some member functions in a template class?
Let's imagine we have something like:
template <class T>
class Increment
{
public:
void init(T initValue)
{
mValue = initValue;
}
T increment()
{
++mValue;
}
T increment(T delta)
{
mValue += delta;
}
private:
T mValue;
};
The objective is to use this class in a way that, in certain cases
we only see the increment() function and in some other cases
we only see the increment(T) member function.
To do that, I can think about something with SFINAE:
class MultipleIncrement
{
typedef int MultipleIncrement_t;
};
class SingleIncrement
{
typedef int SingleIncrement_t;
};
template <class T, class Q>
class Increment
{
public:
void init(T initValue)
{
mValue = initValue;
}
T increment(typename Q::SingleIncrement_t = 0)
{
++mValue;
}
T increment(T delta, typename Q::MultipleIncrement_t = 0)
{
mValue += delta;
}
private:
T mValue;
}
And then use my template like, for example:
Increment<long, MultipleIncrement>
However, the compiler is not letting me do this.
Is there any other way in which this is feasible?
Would it also work if the member function is actually the constructor?
In this case, I would prefer using template specialization. Would something like this help you?
struct SingleIncrement;
struct MultipleIncrement;
template <
class T,
class Policy = SingleIncrement // default template param
>
class Increment
{
T mValue;
public:
Increment(T initValue)
: mValue(initValue)
{}
T increment()
{
++mValue;
}
};
// template specialization for MultipleIncrement
template <class T>
class Increment<T,MultipleIncrement>
{
T mValue;
public:
Increment(T initValue)
: mValue(initValue)
{}
T increment(T delta)
{
mValue += delta;
}
};
Template specialization is good. Inheritance sounds better. Have you considered templating on the inherited base class? (Or is this now considered a faux pax?)
#define SHOW(X) cout << # X " = " << (X) << endl
template <class T>
class A
{
public:
void foo(T t) {SHOW(t); }
};
template <class T, class BASE>
class B : public BASE
{
public:
void bar(T t) {SHOW(t); }
};
int
main()
{
B<int,A<int> > b;
b.foo(1);
b.bar(2);
}
Here is a MWE of how this could be achieved:
#include <iostream>
using namespace std;
struct multi;
struct single;
template<class T, class Q>
struct dummy {
dummy(T value) : m_value(value) { }
// using enable_if_t in template argument
template<class _Q = Q, enable_if_t<is_same<_Q, single>::value && is_same<_Q, Q>::value, int> = 1>
T increment() { return ++m_value; }
// using enable_if_t in method return type
template<class _Q = Q>
enable_if_t<is_same<_Q, multi>::value && is_same<_Q, Q>::value, T>
//enable_if_t<is_same<_Q, multi>::value, T> // (*)
increment(T delta) { return (m_value += delta); }
T m_value;
};
int main() {
dummy<double, multi> m(47.10);
//cout << m.increment() << endl; // error as expected
cout << m.increment(.01) << endl;
dummy<int, single> s(41);
cout << s.increment() << endl;
cout << s.increment<single>() << endl;
//cout << s.increment(1) << endl; // error as expected
//cout << s.increment<multi>(1) << endl; // not an error when using (*)
}
Output
Using c++ (Debian 6.2.1-5) 6.2.1 20161124 this yields:
47.11
42
43
Elaboration
We need to template the methods to make SFINAE work at all. We cannot use something like
std::enable_if_t<std::is_same<_Q, multiple_increment>::value, T> increment() ...
because that fails when instantiating the template dummy<T, single_increment> instead of failing when substituting method template parameters.
Further, we want the user to be able to use the methods without actually providing a method template parameter. So we make the method template parameter _Q default to Q.
Finally, to really force a compiler error when using the unwanted method even when providing a method template parameter, we only enable_if_t the method if method template parameter _Q is actually the same type as the respective class template parameter Q.