Why does the following fail with error: 'a_' was not declared in this scope in the context of Bar::get()?
template <typename N>
class Foo
{
public:
Foo() { }
protected:
N a_;
};
template <typename N>
class Bar : public Foo<N>
{
public:
Bar() : Foo<N>() { }
N get() { return a_; }
};
You need to use the reference this->_a
N get() { return this->a_; }
Related
class Base {};
class Derived : public Base {};
class SomeClass
{
template<typename T>
static void SetContent(T* pChild, OVariant content)
{
LOG_ASSERT(0, "All classes must be specialized!. Please provide implementation for this class.");
}
};
template <>
void SomeClass::SetContent(Base* value)
{
LOG_TRACE("Yay!");
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
When I call foo.SetContent(derived), I get the Assert. Is it not possible for the derived class to use the specialization for it's base class?
You can convert a Derived* to a Base*, but I think you rather want to specialize for all T that have Base as base
#include <type_traits>
#include <iostream>
class Base {};
class Derived : public Base {};
template <typename T,typename = void>
struct impl {
void operator()(T*) {
std::cout <<"All classes must be specialized!. Please provide implementation for this class.\n";
}
};
template <typename T>
struct impl<T,std::enable_if_t<std::is_base_of_v<Base,T>>> {
void operator()(T*) {
std::cout << "Yay\n";
}
};
class SomeClass
{
public:
template<typename T>
static void SetContent(T* pChild)
{
impl<T>{}(pChild);
}
};
struct bar{};
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);
bar b;
foo.SetContent(&b);
}
Output:
Yay
All classes must be specialized!. Please provide implementation for this class.
//want it to call SomeClass::SetContent(Base* value)
Note that if the template argument is deduced, it will be deduced as Derived not as Base and the argument is Derived*. SomeClass::SetContent<Base>(&derived); would already work as expected with your code (because Derived* can be converted to Base*).
A workaround would be to have all SetContent's explicit specializations to form an overload set. You will have to do it yourself:
#include <iostream>
#include <utility>
#include <functional>
class Base {};
class Derived : public Base {};
template <class... T>
struct Overloads : T... {
Overloads(const T &... t) : T(t)... {}
using T::operator()...;
};
template <class R, class... Args>
struct FunctionP {
using F = R(Args...);
FunctionP(F *t) : t_(t) {}
R operator()(Args... args) const {
return std::invoke(t_, std::forward<Args>(args)...);
}
F *t_;
};
struct SomeClass {
template<typename T>
static void SetContent(T *x) {
Overloads o(FunctionP(&SetContentImpl<Base>)); // enumerates all the specializations here
if constexpr (std::is_invocable_v<decltype(o), T *>) {
o(x);
} else {
SetContentImpl(x);
}
}
template<typename T>
static void SetContentImpl(T *) {
std::cout << "1";
}
};
template <>
void SomeClass::SetContentImpl(Base *) {
std::cout << "2";
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
godbolt
I want to do multiple inheritance via template arguments and pass reference to this in each base class, so I can call top level object's method from each base class's method. I can do it with manual inheritance, but I want to be able to do this via templates arguments.
Godbolt link
Godbolt link with manual inheritance
#include <cstdio>
template <typename T>
struct Foo {
Foo(T &t)
: t_(t) {
}
void foo() {
t_.call("foo");
}
T &t_;
};
template <typename T>
struct Bar {
Bar(T &t)
: t_(t) {
}
void bar() {
t_.call("bar");
}
T &t_;
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl>... {
Impl()
: Methods<Impl>(*this)... {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}
I tried this approach, but it gives
type/value mismatch at argument 1 in template parameter list for 'template<class> class ... Methods'
Thanks to #Nicol Bolas, he advised to use static_cast and CRTP for this
#include <cstdio>
template <typename T>
struct Foo {
void foo() {
static_cast<T*>(this)->call("foo");
}
};
template <typename T>
struct Bar {
void bar() {
static_cast<T*>(this)->call("bar");
}
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl<Methods...>>... {
Impl() {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}
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 have an object S. S is composed of layers S0, S1, S2 ... just like a stack of stackable drawers.
I want to create a chain of template classes A, B, C such that:
They represents proxies to different layers of the S object.
Even during template instantiation, C can convert to B, which can convert to A.
A, B, and C have different sets of methods.
The problem is that if I use public inheritance, then C will get the methods of A and B.
Test:
#include <iostream>
// Library
template <typename T>
class A {
public:
void a() {std::cout << "a\n"; }
int s_{0};
};
template <typename T>
class B : public A<T> {
public:
void b() {std::cout << "b\n"; }
};
template <typename T>
class C : public B<T> {
public:
void c() {std::cout << "c\n"; }
};
// User of library write a function like this
template <typename T>
void foo(A<T>& a) { a.a(); }
// The problem:
int main() {
C<int> c;
foo(c);
c.a(); // <--- how to hide this?
return 0;
}
I'm not sure if I understand what you want. But one way to do it is changing the access level of base class member in derived class. For example:
template <typename T>
class C : public B<T> {
public:
void c() { std::cout << "c\n"; }
private:
using A::a; // <-- reduce access level of base class member
};
"Just" need 0 + 1 + 2 + ... + i conversion operators for layer Si
Or one template conversion operator if their attributes are all the same.
But this still need some way to control the conversions.
#include <iostream>
template <typename T>
class A {
public:
A(int& layer) : layer_(layer) {}
void a() {std::cout << "a\n"; }
int s_{0};
private:
int& layer_;
};
template <typename T>
class B {
public:
B(int& layer) : a_(layer) { }
template <template<typename> class X, typename T2>
operator X<T2>() { return a_; }
void b() {std::cout << "b\n"; }
private:
A<T> a_;
};
template <typename T>
class C {
public:
C(int& layer) : b_(layer) {}
template <template<typename> class X, typename T2>
operator X<T2>() { return b_; }
void c() {std::cout << "c\n"; }
private:
B<T> b_;
};
template <typename T>
class D {
public:
D(int& layer) : c_(layer) {}
template <template<typename> class X, typename T2>
operator X<T2>() { return c_; }
void c() {std::cout << "c\n"; }
private:
C<T> c_;
};
template <template<typename> class X, typename T>
void foo(X<T>& a) {
A<T>(a).a();
}
int main() {
int v = 1;
D<int> d(v);
foo(d);
return 0;
}
Consider a class with constexpr non static member function.
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo() const { return k+42; }
}
Is foo() really compile time with any object of B? What about constexpr members?
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo_var = k+42;
}
Will accesses to foo_var be compile time substituted? Will B have foo_var in its object memory layout?
What about std::array<T,N>::size()??