I'm trying to implement a sort of static polymorphism by means of the CRTP and requires clauses.
What I want to achieve is to call a possibly overriden function in a function taking a reference to the CRTP base class.
I made it work with GCC 10 and 11 with the following approach:
#include <iostream>
template<typename T>
class Base
{
public:
void f() const requires T::IsOverridden
{ static_cast<T const *>(this)->f(); }
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
static constexpr bool IsOverridden = true;
public:
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
However, Clang 11 doesn't like this piece of Code:
test.cpp:7:30: error: no member named 'IsOverridden' in 'A'
void f() const requires T::IsOverridden
~~~^
test.cpp:14:18: note: in instantiation of template class 'Base<A>' requested here
class A : public Base<A>
^
test.cpp:7:30: error: no member named 'IsOverridden' in 'B'
void f() const requires T::IsOverridden
~~~^
test.cpp:24:18: note: in instantiation of template class 'Base<B>' requested here
class B : public Base<B> {};
^
Which compiler is right?
Note: I'm using a boolean member to signal overriding because I want it to work with classes nested in template classes and that was the only way I came up with in that case.
I'm posting what I ended up using in case it is useful for somebody else.
I didn't like using a member variable, which I could easily misspell, to signal that the function was overridden.
Instead I used a defaulted std::false_type NTTP for the base-class function, and a std::true_type NTTP for the overloads, so that they can be detected with a requires-expression:
#include <iostream>
#include <type_traits>
template<typename T>
class Base
{
public:
template<std::false_type = std::false_type{}>
requires requires(T const x) { x.template f<std::true_type{}>(); }
void f() const
{ static_cast<T const *>(this)->f(); }
template<std::false_type = std::false_type{}>
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
template<std::true_type = std::true_type{}>
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
GCC 11 accepts the terser syntax template<std::true_type = {}>, but GCC 10 and CLang 12 require the longer template<std::true_type = std::true_type{}>.
for unit testing, I'm trying to create a Factory which meets the following requirements:
(1) It can create arbitrary objects (e.g. Timer and TimerMock)
(2) It returns unique_ptrs to a Base class to these objects (e.g. unique_ptr<TimerInterface>)
(3) The Factory itself can be passed around as a base class pointer too
(4) It shall be possible to call any constructor to create the Object [edit1]using the same factory object[/edit1]
The purpose is to do dependency injection with this factories to be able to exchange objects that are not part of the test with mock objects.
Here's what I have so far:
#include <memory>
#include <iostream>
//"perfect factory method"
//usage: std::unique_ptr<Type> pt(create<Type>(Type-constructor-arguments));
template <typename Type, typename ... ConstructorArgs>
auto create(ConstructorArgs&& ... args){
return std::make_unique<Type>(std::forward<ConstructorArgs>(args)...);
}
//Abstract Factory Base class
template<typename BaseType, typename ... ConstructorArgs>
class IFactory {
public:
virtual ~IFactory() = default;
virtual std::unique_ptr<BaseType> create(ConstructorArgs&& ... args) const = 0;
};
//Abstract Factory class
template <typename BaseType, typename DerivedType, typename ... ConstructorArgs>
class CFactory : public IFactory<BaseType, ConstructorArgs...>
{
public:
using Base = IFactory<BaseType, ConstructorArgs...>;
std::unique_ptr<BaseType> create(ConstructorArgs&& ... args) const override
{
return ::create<DerivedType>(std::forward<ConstructorArgs>(args)...);
}
};
How the real Factory classes are defined:
class TimerInterface {
public:
TimerInterface() = default;
TimerInterface (const char* name);
virtual void whoami() const = 0;
/*...*/
};
class Timer: public TimerInterface {
public:
Timer() = default;
Timer(const char* name) : TimerInterface (name) {}
void whoami() const override { std::cerr << "I'm real!" << std::endl; }
/*...*/
};
class TimerMock : public TimerInterface {
public:
TimerMock () = default;
TimerMock (const char* name) : TimerInterface (name) {}
void whoami() const override { std::cerr << "I fake it!" << std::endl; }
/*...*/
};
using TimerFactory = CFactory<TimerInterface, Timer, const char*>;
using TimerMockFactory = CFactory<TimerInterface, TimerMock, const char*>;
using TimerFactoryInterface = TimerFactory::Base;
And how they are intended to be used:
class ClassUnderTest {
public:
std::unique_ptr<TimerInterface> timer {};
std::unique_ptr<TimerInterface> timer2 {};
ClassUnderTest(const TimerFactoryInterface& factory)
: timer(factory.create("I got a name!"))
//, timer2(factory.create())
{}
};
class Production
{
public:
ClassUnderTest realUsage;
Production() :
realUsage(TimerFactory())
{}
};
class Test
{
public:
ClassUnderTest tested;
Test() :
tested(TimerMockFactory())
{}
};
int main()
{
Production p;
p.realUsage.timer->whoami();
Test t;
t.tested.timer->whoami();
}
My big problem is requirement (4)
ClassUnderTest::timer2 can't be created with the same factory that's used for ClassUnderTest::timer, beause the constructor signatur already needs to be known when defining the CFactory class.
Anyone got an idea?
P.S.: "It can't be done" with an explanation is also an acceptable answer, but not my favourite ;)
Not sure if it helps, but TimerInterface doesn't need to be a complete type when you declare your two std::unique_ptr<TimerInterface> inside ClassUnderTest. Meaning this is legal:
// classundertest.hpp
// A forward-declaration is enough
class TimerInterface;
class TimerFactoryInterface;
class ClassUnderTest {
public:
std::unique_ptr<TimerInterface> timer {};
std::unique_ptr<TimerInterface> timer2 {};
// Both MUST be declared here AND defined in the .cpp for this trick to work
ClassUnderTest(const TimerFactoryInterface& factory);
~ClassUnderTest();
// classundertest.cpp
#include "classundertest.hpp"
// TimerInterface wasn't truly declared until now
#include "TimerInterface.hpp"
ClassUnderTest::ClassUnderTest(const TimerFactoryInterface& factory)
: timer(factory.create("I got a name!"))
, timer2(factory.create("???"))
{}
ClassUnderTest::~ClassUnderTest()
{}
That's basically how unique_ptr-based pimpl work.
You can do it with a std::vector<std::any>, and some index sequences, but it isn't going to be the most pretty or fast solution.
Your factory would be:
template<typename Base>
class IFactory
{
public:
virtual std::unique_ptr<Base> Create(const std::vector<std::any>& args) const = 0;
};
Your concrete factory could then be:
template<typename Base, typename Derived, typename... Args>
class CFactory : IFactory<Base>
{
private:
template<size_t... Indices>
std::unique_ptr<Base> Make(const std::vector<std::any>& args, std::index_sequence<Indices...>) const
{
return std::make_unique<Derived>(std::any_cast<Args>(args[Indices])...);
}
public:
virtual std::unique_ptr<Base> Create(const std::vector<std::any>& args) const
{
return Make(args, std::make_index_sequence<sizeof...(Args)>());
}
};
The only problem here is that you obviously cannot perfectly forward any arguments, you will always end up taking a copy.
It will also throw an std::bad_any_cast if the types passed into the std::any do not match the template.
Here's a simple test I made, and it compiles with both MSVC and Clang with -std=c++17 set:
class A
{
public:
A(int a, int b)
: Val1(a), Val2(b)
{}
A(int a)
: Val1(a), Val2(0)
{}
int Val1, Val2;
};
int main()
{
CFactory<A, A, int> fac1;
CFactory<A, A, int, int> fac2;
auto a1 = fac1.Create({ std::any(10) });
auto a2 = fac2.Create({ std::any(10), std::any(20) });
std::cout << a1->Val1 << " " << a1->Val2 << "\n";
std::cout << a2->Val1 << " " << a2->Val2 << "\n";
}
Edit: This will work for overloaded constructors, as well as any type because its template magic.
#SparkyPotato gave me the idea when stating I'd "have to manually list out the possible constructors and generate overloads for create". I just disliked the manually, so I did it by template meta programming. Thanks for the hint!
#include <memory>
#include <iostream>
#include <tuple>
//"perfect factory method"
//usage: std::unique_ptr<Type> pt(create<Type>(Type-constructor-arguments));
template <typename Type, typename ... ConstructorArgs>
auto create(ConstructorArgs&& ... args){
std::cerr << "calling " << __PRETTY_FUNCTION__ << std::endl;
return std::make_unique<Type>(std::forward<ConstructorArgs>(args)...);
}
//Abstract Factory Variadic class. This is also generic case that ends recursion
template <typename BaseType, typename TupleListOfConstructorArgs>
class IFactory
{
static_assert(std::is_same<TupleListOfConstructorArgs, std::tuple<>>::value, "");
public:
//this method shall never be instatiated, it just exists to satisfy the "using BaseFactory::create" in IFactory
template <typename T> void create(){ static_assert(sizeof(BaseType) + sizeof(T) < 0, ""); }
virtual ~IFactory() = default;
};
//Abstract Factory Variadic class specialization to perform inheritance recursion
template <typename BaseType, typename ... CurrentTupleArgs, typename ... TupleListOfConstructorArgs>
class IFactory<BaseType, std::tuple<std::tuple<CurrentTupleArgs...>, TupleListOfConstructorArgs...>> : public IFactory<BaseType, std::tuple<TupleListOfConstructorArgs...>>
{
public:
using BaseFactory = IFactory<BaseType, std::tuple<TupleListOfConstructorArgs...>>;
using BaseFactory::create;
virtual std::unique_ptr<BaseType> create(const CurrentTupleArgs& ... args) const = 0;
};
//Concrete Factory Variadic class. This is also generic case that ends inheritance recursion
template <typename BaseType, typename DerivedType, typename TupleListOfConstructorArgs, typename FullTupleListOfConstructorArgs>
class CFactory : public IFactory<BaseType, FullTupleListOfConstructorArgs>
{
static_assert(std::is_same<TupleListOfConstructorArgs, std::tuple<>>::value, "");
public:
using Base = IFactory<BaseType, FullTupleListOfConstructorArgs>;
};
//Concrete Factory Variadic class specialization to perform inheritance recursion
template <typename BaseType, typename DerivedType, typename ... CurrentTupleArgs, typename ... TupleListOfConstructorArgs, typename FullTupleListOfConstructorArgs>
class CFactory<BaseType, DerivedType, std::tuple<std::tuple<CurrentTupleArgs...>, TupleListOfConstructorArgs...>, FullTupleListOfConstructorArgs> : public CFactory<BaseType, DerivedType, std::tuple<TupleListOfConstructorArgs...>, FullTupleListOfConstructorArgs>
{
public:
using BaseFactory = CFactory<BaseType, DerivedType, std::tuple<TupleListOfConstructorArgs...>, FullTupleListOfConstructorArgs>;
using BaseFactory::create;
std::unique_ptr<BaseType> create(const CurrentTupleArgs& ... args) const override
{
std::cerr << "calling " << __PRETTY_FUNCTION__ << std::endl;
return ::create<DerivedType>(args...);
}
};
template <typename BaseType, typename DerivedType, typename TupleListOfConstructorArgs>
using CFactoryFrontend = CFactory<BaseType, DerivedType, TupleListOfConstructorArgs, TupleListOfConstructorArgs>;
class TimerInterface {
public:
TimerInterface() = default;
virtual ~TimerInterface() = default;
TimerInterface (const char* name) {}
TimerInterface(int& x, const char* name) { std::cerr << "calling " << __PRETTY_FUNCTION__ << std::endl; }
TimerInterface(const int& x, const char* name) { std::cerr << "calling " << __PRETTY_FUNCTION__ << std::endl; }
virtual void whoami() const = 0;
/*...*/
};
class Timer: public TimerInterface {
public:
Timer() = default;
Timer(const char* name) : TimerInterface (name) {}
Timer(int& x, const char* name) : TimerInterface(x, name) {}
Timer(const int& x, const char* name) : TimerInterface(x, name) {}
void whoami() const override { std::cerr << "I'm real!" << std::endl; }
/*...*/
};
class TimerMock : public TimerInterface {
public:
TimerMock () = default;
TimerMock (const char* name) : TimerInterface (name) {}
TimerMock (int& x, const char* name) : TimerInterface(x, name) {}
TimerMock (const int& x, const char* name) : TimerInterface(x, name) {}
void whoami() const override { std::cerr << "I fake it!" << std::endl; }
/*...*/
};
//using TimerInterfaceConstructors = std::tuple<std::tuple<>, std::tuple<const char*>>;
using Constructors = std::tuple<std::tuple<>, std::tuple<const char*>, std::tuple<int&, const char*>, std::tuple<const int&, const char*>>;
using TestFactory = CFactoryFrontend<TimerInterface, Timer, Constructors>;
using TimerFactory = CFactoryFrontend<TimerInterface, Timer, Constructors>;
using TimerMockFactory = CFactoryFrontend<TimerInterface, TimerMock, Constructors>;
using TimerFactoryInterface = TimerFactory::Base;
class ClassUnderTest {
public:
std::unique_ptr<TimerInterface> timer {};
std::unique_ptr<TimerInterface> timer2 {};
ClassUnderTest(const TimerFactoryInterface& factory)
: timer(factory.create("I got a name!"))
, timer2(factory.create())
{}
};
class Production
{
public:
ClassUnderTest realUsage;
Production() :
realUsage(TimerFactory())
{}
};
class Test
{
public:
ClassUnderTest tested;
Test() :
tested(TimerMockFactory())
{}
};
int main()
{
Production p;
p.realUsage.timer->whoami();
Test t;
t.tested.timer->whoami();
TestFactory tf;
TimerFactoryInterface& tfi(tf);
const char* x = "X";
tfi.create();
tfi.create(x);
int y;
const int cy = 17;
tfi.create(y, x);
tfi.create(cy, "name");
::create<Timer>(x);
}
It compiles using GCC-6 and newer and clang with -std=c++-14
Suppose that all classes of a hierarchy implement a template member function g. All classes share the same implementation of two other functions f1 and f2 that call this template:
struct A {
virtual void f1() {
g(5);
}
virtual void f2() {
g(5.5);
}
private:
template <typename T> void g(T) {std::cout << "In A" << std::endl;}
};
struct B: A {
// Can I get rid of this duplicate code?
virtual void f1() {
g(5);
}
virtual void f2() {
g(5.5);
}
private:
template <typename T> void g(T) {std::cout << "In B" << std::endl;}
};
struct C: A {
// Can I get rid of this duplicate code?
virtual void f1() {
g(5);
}
virtual void f2() {
g(5.5);
}
private:
template <typename T> void g(T) {std::cout << "In C" << std::endl;}
};
int main()
{
B b;
A &a = b;
a.f1();
return 0;
}
Since the implementations of f1 and f2 are identical in all the classes, how can I get rid of the duplicate code and still have the polymorphic call in main work as expected (i.e produce the output "In B")?
Note that the implementations of f1 and f2 in A, B, and C are not identical. Let's restrict it to f1s. One calls a function named ::A::g<int>, another one calls a function named ::B::g<int>, and the third one calls a function named ::C::g<int>. They are very far from identical.
The best you could do is have a CRTP-style base:
template <class Derived>
struct DelegateToG : public A
{
void f1() override
{
static_cast<Derived*>(this)->g(5);
}
void f2() override
{
static_cast<Derived*>(this)->g(5.5);
}
};
class B : public DelegateToG<B>
{
friend DelegateToG<B>;
private:
template <class T> void g(T) { /*...*/ }
};
class C : public DelegateToG<C>
{
friend DelegateToG<C>;
private:
template <class T> void g(T) { /*...*/ }
};
You can just factor out the class-specific things that the template function uses, such as (in your example) the class name:
#include <iostream>
using namespace std;
class A
{
private:
virtual auto classname() const -> char const* { return "A"; }
protected:
template <typename T> void g(T) {cout << "In " << classname() << endl;}
public:
virtual void f1() { g(5); }
virtual void f2() { g(5.5); }
};
class B
: public A
{
private:
auto classname() const -> char const* override { return "B"; }
};
class C
: public A
{
private:
auto classname() const -> char const* override { return "C"; }
};
auto main()
-> int
{ static_cast<A&&>( B() ).f1(); }
I was wondering if there are pattern/ways to inherit template functions ?
Template functions can not be virtual so if my base class has a template function and my derived class has the same, the function of the base class will always be called in the following example :
struct Base {
Base() {}
template < typename T >
void do_something(T& t) const {
t << "Base" << std::endl ;
}
};
struct Foo : Base {
Foo() : Base () {}
template < typename T >
void do_something(T& t) const {
t << "Foo" << std::endl ;
}
};
struct Bar : Foo {
Bar() : Foo() {}
template < typename T >
void do_something(T& t) const {
t << "Bar" << std::endl ;
}
};
int main(int argc, char** argv)
{
Base *b = new Base() ;
Base *f = new Foo() ;
Base *ba = new Bar() ;
b->do_something(std::cout) ;
f->do_something(std::cout) ;
ba->do_something(std::cout) ;
return 0 ;
}
So this program always print :
Base
Base
Base
Is there a way to make my program print :
Base
Foo
Bar
Actually the only way I found for doing that is to make a static_cast :
...
static_cast<Foo*>(f)->do_something(std::cout) ;
static_cast<Bar*>(ba)->do_something(std::cout) ;
...
Is there any pattern or elegant way to encapsulate the cast so that it will be unnoticeable from the function call ?
Thanks for your replies
You can almost always do what you need by splitting the function into smaller parts, making each part templated if necessary, or virtual if necessary. In this example, that's as simple as:
struct Base {
Base() {}
template < typename T >
void do_something(T& t) const {
t << something_piece() << std::endl ;
}
virtual const char* something_piece() const {
return "Base";
}
};
struct Foo : Base {
Foo() : Base () {}
const char* something_piece() const {
return "Foo";
}
};
struct Bar : Foo {
Bar() : Foo() {}
const char* something_piece() const {
return "Bar";
}
};
It can get more complicated than that, but the idea is pretty powerful at combining compile-time and run-time differences.
Do you have the option to change the struct to a Template class rather than template methods?
If so:
Template<typename T>
struct Base
{
public:
virtual void doSomething();
};
Template<typename T>
struct Foo : Base<T>
{
public:
virtual void doSomething();
};
I have a method which is templated and I want it to call a different method depending on the template. The reason I have this is so that the caller does not need to create an Object of type B just to get the correct implementation called, instead they should be able to just choose by the implementation by templating.
The problem is i'm receiving reference type to a const as the template T and I do not know how to use this to choose the correct overloaded method. Ideally this would also work if T were not a reference type. Any idea?
Note: I can't use template specialization because I need the impl virtual.
#include <iostream>
using namespace std;
class A {};
class B {};
class C {
public:
template <typename T>
void f() {
// T = const B&
impl(T()); // error: value-initialization of reference type ‘const B&’
}
protected:
virtual void impl(const A& a) {
cout << "A";
}
virtual void impl(const B& b) {
cout << "B";
}
};
int main() {
C c;
const B &b2 = B();
c.f<decltype(b2)>(); // T = const B&
return 0;
}
If you want to get a type [more] likely to be constructible, you should remove any references, e.g., using std::remove_reference<T> and all qualifiers, e.g., using std::remove_cv<T>. ... or, just std::decay<T> the type which also transforms arrays into pointers:
template <typename T>
void f() {
impl(typename std::decay<T>::type());
}
You can still use template specialization through a helper private template dispatcher to call correct version of impl - which can still be virtual. Like this, compiles and runs
#include <iostream>
using namespace std;
class A {};
class B {};
class C {
public:
template <typename T>
void f() {
// T = const B&
impl_dispatch<T>(); // error: value-initialization of reference type ‘const B&’
}
protected:
virtual void impl(const A& a) {
cout << "A";
}
virtual void impl(const B& b) {
cout << "B";
}
private:
template <typename T>
void impl_dispatch();
};
template <> void C::impl_dispatch<A const &>()
{
impl(B());
}
template <> void C::impl_dispatch<B const &>()
{
impl(A());
}
int main() {
C c;
const B &b2 = B();
c.f<decltype(b2)>(); // T = const B&
return 0;
}