Resolving CRTP initialization order - c++

I have some CRTP dependency that I am not sure how to resolve. Ideally I want to put as many things as possible in the base class, like functions, so I do not have to redefine those for every class that inherits those. This seems to cause an issue with the initialization order, where result_type is dependent on the type that is yet to be initialized. Here is an example: https://godbolt.org/z/YpfcPB
And here is the code:
template<typename T>
struct CRTP_Derived;
template<typename Derived>
struct CRTP
{
using result_type = typename Derived::result_type;
};
template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>>
{
using result_type = T;
};
int main()
{
CRTP_Derived<int> a;
return 0;
}

I've also used a separate traits type for issues like this. You can reduce the needed boilerplate a little if you make the traits a second template parameter, instead of requiring users to specialize a separate template:
template<typename Derived, typename Traits>
struct CRTP
{
using result_type = typename Traits::result_type;
};
template<typename T>
struct CRTP_Derived_Traits
{
using result_type = T;
};
template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>, CRTP_Derived_Traits<T>>
{
};
int main()
{
CRTP_Derived<int> a;
return 0;
}

A workaround I found is taking out the typedef in a separate class, still I would be glad to see other solutions.
https://godbolt.org/z/a7NCE2
template<typename T>
struct CRTP_Derived;
template<typename Derived>
struct traits;
template<typename T>
struct traits<CRTP_Derived<T>>
{
using result_type = T;
};
template<typename Derived>
struct CRTP
{
using result_type = typename traits<Derived>::result_type;
};
template<typename T>
struct CRTP_Derived : public CRTP<CRTP_Derived<T>>
{
using result_type = T;
};
int main()
{
CRTP_Derived<int> a;
return 0;
}

Related

Get deepest class in CRTP inheritance chain

I would like to know how to solve the following problem (C++17):
suppose there are several template classes, inherited from each other in CRTP-like fashion (single inheritance only). For a given instantiated template base class, find the class that is furthest from it down the inheritance chain.
I first thought that is should be pretty easy, but was not able to accomplish this.
To simplify, suppose that every root and every intermediate class has using DerivedT = Derived in its public area.
Example:
template <class T>
struct GetDeepest {
using Type = ...;
};
template <class T>
struct A {
using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
GetDeepest<A<D>>::Type == D;
GetDeepest<B<C>>::Type == C;
GetDeepest<A<B<C>>>::Type == C;
...
First implementation I've tried:
template <class T>
struct GetDeepest {
template <class Test, class = typename Test::DerivedT>
static std::true_type Helper(const Test&);
static std::false_type Helper(...);
using HelperType = decltype(Helper(std::declval<T>()));
using Type = std::conditional_t<std::is_same_v<std::true_type, HelperType>,
GetDeepest<typename T::DerivedT>::Type,
T>;
};
Second implementation I've tried:
template <class T>
struct HasNext {
template <class Test, class = typename Test::DerivedT>
static std::true_type Helper(const Test&);
static std::false_type Helper(...);
using HelperType = decltype(Helper(std::declval<T>()));
static const bool value = std::is_same_v<std::true_type, HelperType>;
};
template <class T>
auto GetDeepestHelper(const T& val) {
if constexpr(HasNext<T>::value) {
return GetDeepestHelper(std::declval<typename T::DerivedT>());
} else {
return val;
}
}
template <class T>
struct GetDeepest {
using Type = decltype(GetDeepestLevelHelper(std::declval<T>()));
};
None of them compile.
First one -- because of incomplete type of GetDeepest<T> in statement using Type = ..., second because of recursive call of a function with auto as a return type.
Is it even possible to implement GetDeepest<T> class with such properties? Now I'm very curious, even if it might be not the best way to accomplish what I want.
Thanks!
I'm not sure if I fully understand the question so feel free to ask me in comments.
But I think this should work:
#include <type_traits>
template<typename T>
struct GetDeepest
{
using Type = T;
};
template<template<typename> class DT, typename T>
struct GetDeepest<DT<T>>
{
using Type = typename GetDeepest<T>::Type;
};
template <class T>
struct A {
using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
int main()
{
static_assert(std::is_same<GetDeepest<A<D>>::Type, D>::value);
static_assert(std::is_same<GetDeepest<B<C>>::Type, C>::value);
static_assert(std::is_same<GetDeepest<A<B<C>>>::Type, C>::value);
}

Is there a way to resolve this template circular dependency

Is there a general approach to solve this type of circular dependencies in template or is it impossible to make work?
#include <tuple>
template<class... T>
struct A {
std::tuple<T...> t;
};
template<class type_of_A>
struct D1 {
type_of_A* p;
};
template<class type_of_A>
struct D2 {
type_of_A* p;
};
using A_type = A<D1<???>, D2<???>>; // <------
int main() { }
As usual, insert a named indirection into the mix to break the infinite recursion:
template<class... T>
struct A {
std::tuple<T...> t;
};
template<class type_of_A>
struct D1 {
typename type_of_A::type* p; // Indirection
};
template<class type_of_A>
struct D2 {
typename type_of_A::type* p; // Indirection
};
// Type factory while we're at it
template <template <class> class... Ds>
struct MakeA {
using type = A<Ds<MakeA>...>; // Hey, that's me!
};
using A_type = typename MakeA<D1, D2>::type;
The behaviour of MakeAs injected-class-name is a bonus, but we could spell it out as MakeA<Ds...>.
See it live on Coliru

Is there an idiom/design pattern for restricting templates?

How do one restrict the typename T to specific type?
Consider this:
template <typename T>
struct Worker {
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
This is what I usually end up doing:
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0;}
}
struct WorkabelTypeA : WorkableType {
std::string toString() { return "A"; }
int get() { return 1;}
};
//Similarly
struct WorkableTypeB : WorkableType;
And use static assert and std::is_base_of:
template <typename T>
struct Worker {
static_assert(std::is_base_of<WorkableType, T>::value, "Needs workable type");
// Do something with T
};
Is there any other design pattern, a more C++ way to restrict accidental instantiation of bad typed templates?
Edit: Seems like this would be better solved with C++ Concepts when it becomes the standard. Until then i guess, static_assert is probably more cleaner and verbose than enable_if.
You could use SFINAE and template specialisation:
// type trait that evaluates always to false to use in the primary template
template<typename ... T> struct always_false : std::false_type { };
// primary template
template<typename T, typename Enable = void>
struct Worker {
static_assert(always_false<T, Enable>::value, "Needs workable type");
};
// specialisation
template<typename T>
struct Worker<T, std::enable_if_t<std::is_base_of<WorkableType, T>::value>> {
...
};
You can create traits and check that in your class, So, no need of inheritance. For example:
template <typename T>
using toString_t = decltype(std::declval<T>().toString());
template <typename T>
using get_t = decltype(std::declval<T>().get());
// Use C++17, but can be done in C++11
template <typename T>
using has_toString = std::is_detected<toString_t, T>;
template <typename T>
using has_get = std::is_detected<get_t, T>;
And then
template <typename T>
struct Worker {
static_assert(has_toString<T>::value, "T should have toString");
static_assert(has_get<T>::value, "T should have get");
};
Demo
If you know exactly which types you want to allow, then a traits class is a succinct way to do it:
#include <utility>
// by default nothing is workable
template<class T>
struct is_workable : std::false_type
{
};
template <typename T>
struct Worker {
static_assert(is_workable<T>(), "not a workable type");
// T can only be certain type allowing specific functionality.
// i.e T needs to be a product of some interface, support some functions, say T::toString(), T::print(), T::get().
// Do something with T
};
// define a worker
struct A {};
// make it workable
template<> struct is_workable<A> : std::true_type {};
// define another worker but forget to make it workable
struct B {};
int main()
{
Worker<A> wa{};
// Worker<B> wb{}; // compile error - not workable
};
You can use specializations as it follows:
#include<string>
struct WorkableType {
std::string toString() { return ""; }
int get() { return 0; }
};
struct A {};
struct B {};
template<typename> struct Worker;
template<> struct Worker<A>: WorkableType {};
int main() {
Worker<A> wa;
// this won't compile
// Worker<B> wb;
}

Templates arguments not fulfulling all requirements

This is possible:
struct A {
//void f(); < not declared in struct A
};
template<typename T>
struct Wrapper {
T t;
void call_f() { t.f(); }
};
int main() {
Wrapper<A> w;
}
This compiled fine, as long as w.call_f() is not called. w.call_f() can not be instantiated because A::f does not exist.
I'm having a situation with such a wrapper template that gets used with different T types, which do not always implement all parts of the interface. (Mainly to avoid code duplication).
This does not work:
struct A {
//using i_type = int; < not declared/defined
};
template<typename T>
struct Wrapper {
using its_i_type = typename T::i_type;
// compile error, even if `i_type` gets never used
};
int main() {
Wrapper<A> w;
}
neither does this:
struct A {
//using i_type = int; < not declared/defined
};
template<typename T>
struct Wrapper {
typename T::i_type call_f() { return 0; }
// does not compile, even if `call_f()` is never instantiated
};
int main() {
Wrapper<A> w;
}
Is there a good way to handle these situations, without a lot of code duplication (like a specialization for Wrapper, etc.)?
You can defer the type deduction of its_i_type. Basically, you create a simple wrapper that you must go through.
To extend it to other types you require, (I wanted to suggest type_traits-like solution, but since you don't want specializations) you could define all the types you need:
template<typename T>
struct Wrapper {
private:
template<typename U> struct i_typper { using type = typename U::i_type; };
template<typename U> struct k_typper { using type = typename U::k_type; };
template<typename U> struct p_typper { using type = typename U::p_type; };
public:
using i_trait = i_typper<T>;
using k_trait = k_typper<T>;
using p_trait = p_typper<T>;
};
Example:
struct A { using i_type = int; };
struct B { using i_type = int; using k_type = float; };
int main() {
Wrapper<A> w; //Works now.
Wrapper<A>::i_trait::type mk1; //Works
Wrapper<A>::k_trait::type mk2; //Fails, not defined
Wrapper<B>::i_trait::type mk3; //Works
Wrapper<B>::k_trait::type mk4; //Works
}
For the case of:
template<typename T>
struct Wrapper {
typename T::i_type call_f() { return 0; }
// does not compile, even if `call_f()` is never instantiated
};
You have few options here:
make that function a member function template
Use some form of type_traits mechanism, which will still involve specialization
Go the way of abstracting common Wrapper stuff in a base class WrapperBase;
For the first option, you'll have to modify it a bit to further defer deduction
template<typename T>
struct Wrapper {
private:
template<typename U, typename> struct i_typper { using type = typename U::i_type; };
template<typename U, typename> struct k_typper { using type = typename U::k_type; };
template<typename U, typename> struct p_typper { using type = typename U::p_type; };
public:
using i_trait = i_typper<T, void>;
using k_trait = k_typper<T, void>;
using p_trait = p_typper<T, void>;
template<typename U = void>
typename k_typper<T, U>::type call_f() { return 0; }
};
I'll leave the second option as an exercise: (it may end up being something like:
template<typename T>
struct wrapper_traits {
....
};
template<>
struct wrapper_traits<A>{
using ....
};
template<typename T>
struct Wrapper {
....
public:
using i_trait = wrapper_traits<T>;
using k_trait = wrapper_traits<T>;
using p_trait = wrapper_traits<T>;
};
Jarod's answer is simpler. But this will work if you do not have access to std::experimental, or your company code policy forbids you...
With std::experimental::is_detected, you may do
template<typename T>
using i_type_t = typename T::i_type;
template<typename T>
struct Wrapper {
using its_i_type = typename std::experimental::detected_t<i_type_t, T>;
// would be T::i_type or std::experimental::nonesuch
};
Or to better handle case, something like:
template<typename T, bool = std::experimental::is_detected<i_type_t, T>::value>
struct WrapperWithIType {
// Empty for false case.
};
template<typename T>
struct WrapperWithIType<T, true> {
using its_i_type = i_type_t<T>;
its_i_type call_f() { return 0; }
};
and then
template<typename T>
struct Wrapper : WrapperWithIType<T> {
// Common stuff
};

Mechanism to create "template" objects in C++

I want to be able to initialize objects with some default values, but to do this from external code(not embedded in the class itself). The objects are exposed to external editor and I don't want to set the same values again and again and change only some values that are different. As I have already template classes I want to do this from the "traits" class.
This is a simple samle of what I want to achieve:
template<typename Traits>
class Test
{
public:
Test()
{
//if Traits has Init init function call Traits::Init(this)
}
private:
typename Traits::Type value;
friend Traits;
};
struct TestTraits
{
typedef std::string Type;
};
struct TestTraitsInit
{
typedef int Type;
static void Init(Test<TestTraitsInit>* obj)
{
obj->value = 0;
}
};
int main()
{
Test<TestTraits> obj1;
Test<TestTraitsInit> obj2;
}
As you can see it makes sense to have Init() only in some cases. Is it possible to check if class Traits has Init() function and call it only when it exists?
I know that a very simple solution would be to have empty Init() functions, but I want a better solution:)
You could create some class template maybe_call_init with a proper SFINAE-constrained specialization based on expression SFINAE:
template<typename T, typename = void>
struct maybe_call_init
{
static void maybe_call(Test<T>* obj) { }
};
template<typename T>
struct maybe_call_init<T,
decltype(T::Init(std::declval<Test<T>*>()), void(0))>
{
static void maybe_call(Test<T>* obj) { T::Init(obj); }
};
Given a trait T, maybe_call_init<T>::maybe_call(obj) will call T::Init(obj) if T defines such a function, and it will do nothing otherwise.
Then, you could use it in your original class template this way:
template<typename Traits>
class Test
{
public:
Test()
{
maybe_call_init<Traits>::maybe_call(this);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
private:
typename Traits::Type value;
friend Traits;
};
The above solution is a bit rudimental, and could be improved by hiding the maybe_call_init class template and its specialization in a detail namespace, providing a helper function to do the instantiation work. So given this machinery:
namespace detail
{
template<typename T, typename U, typename = void>
struct maybe_call_init
{
static void maybe_call(U* obj) { }
};
template<typename T, typename U>
struct maybe_call_init<T, U,
decltype(T::Init(std::declval<U*>()), void(0))>
{
static void maybe_call(U* obj) { T::Init(obj); }
};
}
template<template<typename> class T, typename U>
void maybe_call_init(T<U>* obj)
{
detail::maybe_call_init<U, T<U>>::maybe_call(obj);
}
The constructor of your original Test class may now look like this:
template<typename Traits>
class Test
{
public:
Test()
{
maybe_call_init(this);
// ^^^^^^^^^^^^^^^^^^^^^
}
public:
typename Traits::Type value;
friend Traits;
};
Here is a live example.