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;
}
Related
#include <functional>
#include <iostream>
class Plain {
public:
template <typename Type>
void member_function(const Type& s) {
std::cout << "Recived: " << s << std::endl;
}
};
template <typename Type>
class Templated : private Plain {
public:
};
int main() {
Plain b;
b.member_function<int>(10); // done!
Templated<int> d;
// d.member_function(); /* how to achive this */
return 0;
}
I am trying to call the member function in class Plain by two method:
createing non-templated class and padding type while calling function
Plain p;
p.member_function<int>();
passing type while creating class and calling without template param
Templated<int> t;
t.member_function(); // achive this
I tried doing binding the function in derived class like
struct Plain{
template<typename T>
static void member_function(const T& s){std::cout << s << std::endl;}
}
template<typename T>
struct Templated : private Plain {
std::function<void(const T&)> print = Templated::Plain::member_function;
}
and after that I was able to do
Templated t<std::string>;
t.print();
When you use private inheritance the methods in Plain are inaccessible to outside code, and you need to have something inside of Templated make the call to the method in Plain; you can do so, or alternatively you could use public inheritance and be able to hit it directly.
class Plain {
public:
template <typename T>
void print(const T & s) {
std::cout << "Received: " << s << std::endl;
}
};
template <typename T>
class Templated : private Plain {
public:
void print(const T & s) {
Plain::print<T>(s);
}
};
template <typename T>
class Alternative : public Plain {};
int main() {
Templated<int> t;
t.print(3); // This could work
Alternative<int> a;
a.print(4); // As could this
return 0;
}
I found a workaround
#include <functional>
#include <iostream>
using namespace std::placeholders;
struct Test {
template <typename Type>
void foo(const Type&) {
std::cout << "I am just a foo..." << std::endl;
return;
}
};
template <typename T>
struct Foo {
private:
Test* obj;
public:
Foo() : obj(new Test) {}
std::function<void(const int&)> foo = std::bind(&Test::foo<T>, obj, _1);
~Foo() { delete obj; }
};
int main() {
Foo<int> me;
me.foo(10);
Test t;
t.foo<int>(89);
std::cout << std::endl;
return 0;
}
To implement a property system for polymorphic objects, I first declared the following structure:
enum class access_rights_t
{
NONE = 0,
READ = 1 << 0,
WRITE = 1 << 1,
READ_WRITE = READ | WRITE
};
struct property_format
{
type_index type;
string name;
access_rights_t access_rights;
};
So a property is defined with a type, a name and access rights (read-only, write-only or read-write). Then I started the property class as follows:
template<typename Base>
class property : property_format
{
public:
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
template<typename Derived, typename T>
using set_t = function<void(Derived&, const T&)>;
private:
get_t<Base, any> get_f;
set_t<Base, any> set_f;
The property is associated to a base type, but may (and will) be filled with accessors associated to an instance of a derived type. The accessors will be encapsulated with functions accessing std::any objects on an instance of type Base. The get and set methods are declared as follows (type checking are not shown here to make the code minimal):
public:
template<typename T>
T get(const Base& b) const
{
return any_cast<T>(this->get_f(b));
}
template<typename T>
void set(Base& b, const T& value_)
{
this->set_f(b, any(value_));
}
Then the constructors (access rights are set to NONE to make the code minimal):
template<typename Derived, typename T>
property(
const string& name_,
get_t<Derived, T> get_,
set_t<Derived, T> set_ = nullptr
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
set_f{caller<Derived, T>{set_}}
{
}
template<typename Derived, typename T>
property(
const string& name_,
set_t<Derived, T> set_
):
property{
name_,
nullptr,
set_
}
{
}
The functions passed as arguments are encapsulated through the helper structure caller:
private:
template<typename Derived, typename T>
struct caller
{
get_t<Derived, T> get_f;
set_t<Derived, T> set_f;
caller(get_t<Derived, T> get_):
get_f{get_}
{
}
caller(set_t<Derived, T> set_):
set_f{set_}
{
}
any operator()(const Base& object_)
{
return any{
this->get_f(
static_cast<const Derived&>(object_)
)
};
}
void operator()(Base& object_, const any& value_)
{
this->set_f(
static_cast<Derived&>(object_),
any_cast<Value>(value_)
);
}
};
Now, considering these dummy classes.
struct foo
{
};
struct bar : foo
{
int i, j;
bar(int i_, int j_):
i{i_},
j{j_}
{
}
int get_i() const {return i;}
void set_i(const int& i_) { this->i = i_; }
};
I can write the following code:
int main()
{
// declare accessors through bar methods
property<foo>::get_t<bar, int> get_i = &bar::get_i;
property<foo>::set_t<bar, int> set_i = &bar::set_i;
// declare a read-write property
property<foo> p_i{"bar_i", get_i, set_i};
// declare a getter through a lambda
property<foo>::get_t<bar, int> get_j = [](const bar& b_){ return b_.j; };
// declare a read-only property
property<foo> p_j{"bar_j", get_j};
// dummy usage
bar b{42, 24};
foo& f = b;
cout << p_i.get<int>(f) << " " << p_j.get<int>(f) << endl;
p_i.set<int>(f, 43);
cout << p_i.get<int>(f) << endl;
}
My problem is that template type deduction doesn't allow me to declare a property directly passing the accessors as arguments, as in:
property<foo> p_i{"bar_i", &bar::get_i, &bar::set_i};
Which produces the following error:
prog.cc:62:5: note: template argument deduction/substitution failed:
prog.cc:149:50: note: mismatched types std::function<void(Type&, const Value&)> and int (bar::*)() const
property<foo> p_i{"bar_i", &bar::get_i, set_i};
Is there a way to address this problem while keeping the code "simple"?
A complete live example is available here.
std::function is a type erasure type. Type erasure types are not suitable for deduction.
template<typename Derived, typename T>
using get_t = function<T(const Derived&)>;
get_t is an alias to a type erasure type. Ditto.
Create traits classes:
template<class T>
struct gettor_traits : std::false_type {};
this will tell you if T is a valid gettor, and if so what its input and output types are. Similarly for settor_traits.
So
template<class T, class Derived>
struct gettor_traits< std::function<T(Derived const&)> >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
template<class T, class Derived>
struct gettor_traits< T(Derived::*)() >:
std::true_type
{
using return_type = T;
using argument_type = Derived;
};
etc.
Now we got back to the property ctor:
template<class Gettor,
std::enable_if_t< gettor_traits<Gettor>{}, int> =0,
class T = typename gettor_traits<Gettor>::return_value,
class Derived = typename gettor_traits<Gettor>::argument_type
>
property(
const string& name_,
Gettor get_
):
property_format{
typeid(T),
name_,
access_rights_t::NONE
},
get_f{caller<Derived, T>{get_}},
nullptr
{
}
where we use SFINAE to ensure that our Gettor passes muster, and the traits class to extract the types we care about.
There is going to be lots of work here. But it is write-once work.
My preferred syntax in these cases would be:
std::cout << (f->*p_i)();
and
(f->*p_i)(7);
where the property acts like a member function pointer, or even
(f->*p_i) = 7;
std::cout << (f->*p_i);
where the property transparently acts like a member variable pointer.
In both cases, through overload of ->*, and in the second case via returning a pseudo-reference from ->*.
At the end of this answer is a slightly different approach. I will begin with the general problem though.
The problem is &bar::get_i is a function pointer to a member function while your alias is creating a function object which needs the class as additional template parameter.
Some examples:
Non member function:
#include <functional>
void a(int i) {};
void f(std::function<void(int)> func)
{
}
int main()
{
f(&a);
return 0;
}
This works fine. Now if I change a into a struct:
#include <functional>
struct A
{
void a(int i) {};
};
void f(std::function<void(int)> func)
{
}
int main()
{
f(std::function<void(int)>(&A::a));
return 0;
}
this gets the error:
error: no matching function for call to std::function<void(int)>::function(void (A::*)(int))'
because the std::function object also need the base class (as you do with your alias declaration)
You need a std::function<void(A,int)>
You cannot make your example much better though.
A way to make it a "bit" more easier than your example would maybe be this approach using CRTP.
#include <functional>
template <typename Class>
struct funcPtr
{
template <typename type>
using fun = std::function<void(Class,type)>;
};
struct A : public funcPtr<A>
{
void a(int i) {};
};
void f(A::fun<int> func)
{
};
int main()
{
f(A::fun<int>(&A::a));
return 0;
}
And each your "derived" classes derives from a funcPtr class which "auto generates" the specific alias declaration.
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
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();
}
};
If I have a class A
template <typename T>
class A { public: void print() const; };
I can write specific version of my methode print for specific template values my doing
template<> void A<bool>::print() const { printf("A w/ type bool\n"); }
template<> void A<int>::print() const { printf("A w/ type int\n"); }
and the calling the method print will just call the code of the good implementation (of the compiler tell me if I don't have an implementation for a specific template.
Now, if I have multiples types in my class B's template
template <typename T1, typename T2>
class B { public: void print() const; };
and if I try to do the same as before, let's say for T2
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
I get an compiler error :
error: invalid use of incomplete type 'class B<T1,bool>'
error: declaration of 'class B<T1, bool>'
What am I doing wrong ?
EDIT
My real life B class contains other methods with I do not want to specify (they work in the general case)
Having a partially specified class decalred makes that those generic methods aren't natively availlable
You can't partial specialize a function/method.
But you can partial specialize the whole class:
template <typename T1, typename T2> class B;
template<typename T1> class B<T1, bool>
{
public:
void print() const { printf("B w/ type bool\n"); }
};
What am I doing wrong?
template<> void A<bool>::print() const { printf("A w/ type bool\n"); }
template<> void A<int>::print() const { printf("A w/ type int\n"); }
These member functions are like normal functions, they are not templates with un-substituted parameters, so you are just providing definitions for the symbols, which will be used when those functions get called. (And like normal functions, if those definitions are in a header and you don't declare them inline you will get multiple definitions errors for them.)
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
This is not the same, this is providing a definition for a member function of a class template partial specialization. i.e. it's a template that will be used to generate code for the member of that partial specialization, but you haven't declared any such partial specialization, so you can't define its members.
You can make it compile by defining the partial specialization first:
// primary template
template <typename T1, typename T2>
class B { public: void print() const; };
// partial specialization
template<typename T1>
class B<T1,bool> { public: void print() const; };
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
However it is often inconvenient to have to repeat the entire class template definition just to define a partial specialization for one or two members, so it might be worth taking one of the alternative designs shown in other answers.
With templates it's best to decompose each part of the specialisation into its own template function or traits class.
Here's a clean way to do what you want:
template<typename T>
const char* type_name()
{
return "unknown";
};
template<>
const char* type_name<int>()
{
return "int";
}
template<>
const char* type_name<bool>()
{
return "bool";
}
struct foo {};
template<>
const char* type_name<foo>()
{
return "my custom foo";
}
struct bar {};
template <typename T>
class A {
public:
void print() const {
cout << "A w/ type " << type_name<T>() << '\n';
}
};
int main() {
A<bool> ab;
A<int> ai;
A<foo> af;
A<bar> abar;
ab.print();
ai.print();
af.print();
abar.print();
return 0;
}
output:
A w/ type bool
A w/ type int
A w/ type my custom foo
A w/ type unknown
Program ended with exit code: 0
With tag dispatching, you might do:
#include <iostream>
template<typename A, typename B>
class X
{
private:
template <typename U> struct Tag {};
template <typename U>
void print(Tag<U>) const;
void print(Tag<bool>) const { std::cout << "bool\n"; }
void print(Tag<int>) const{ std::cout << "int\n"; }
public:
void print() const { print(Tag<B>()); }
};
int main()
{
X<void, bool>().print();
X<void, int>().print();
}