Mechanism to create "template" objects in C++ - 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.

Related

Resolving CRTP initialization order

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;
}

Return type agnostic template class member function

I have a class like:
tempate<class TReturn>
struct MyClass {
template<class T>
TReturn doSomething(const T &t) {
// Do something
return someValue;
}
};
Now TReturn can be anything even void but in case it is void I want no return statement at the end and some minor different code in the function. What I want is a different function body depending on the return type. I'm using C++11 so if constexpr is not possible for me. Is there any way to to this in plain C++11?
You can provide a specialization of your class for void:
tempate<>
struct MyClass<void> {
template<class T>
void doSomething(const T &t) {
// Do something else
}
};
If the class is in fact larger than you show and you want to specialize just this one function and not the whole thing, then a) it was probably unwise to make TReturn a parameter of the class when only a small part of the class depends on it, but b) there are ways to simulate that. E.g. you could sort of "partially specialize" the method by indirecting through a helper class (unlike function templates, class templates allow partial specialization). Something like this:
tempate<class TReturn> struct MyClass;
namespace internal {
template <typename TReturn, typename T>
class MyClassDoSomethingHelper {
static TReturn Run(MyClass<TReturn>* that, const T &t) {
// do something
return someValue;
}
};
template <typename T>
class MyClassDoSomethingHelper<void, T> {
static void Run(MyClass<void>* that, const T &t) {
// do something else
}
};
} // namespace internal
tempate<class TReturn>
struct MyClass {
template<class T>
TReturn doSomething(const T &t) {
return internal::MyClassDoSomethingHelper<TReturn, T>::Run(this, t);
}
};

Change class API depending on template parameter at class creation

I was looking to create a class that under specific template instantiation would expose a different API. It has common functions, but a few should be disabled in the case that the user will use a specific instantiation of the class. Something like this:
VarApi<T1> v1;
v1.common();
v1.funcA1();
// v1.funcA2(); // ERROR
v1.funcA1_2();
VarApi<T2> v2;
v1.common();
// v2.funcA1(); // ERROR
v2.funcA2();
v2.funcA1_2();
VarApi<T3> v3;
v3.common();
// v2.funcA1(); // ERROR
// v2.funcA2(); // ERROR
// v1.funcA1_2(); // ERROR
I found that you could achieve this with SFINAE and std::enable_if like this:
enum Type { T1, T2, T3 };
template <Type TType> struct VarApi {
void common() { }
template <Type T = TType,
typename = typename std::enable_if<T == T1>::type>
void funcA1() { }
template <Type T = TType,
typename = typename std::enable_if<T == T2>::type >
void funcA2() { }
template <Type T = TType,
typename = typename std::enable_if<T == T1 || T == T2>::type >
void funcA1_2() { }
template <Type T = TType,
typename = typename std::enable_if<T == T3>::type >
void funcA3() { }
};
This works and achieves the functionality above. The problem is that the user can still override this with:
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
Is there a way to prevent this case?
This works and achieves the functionality above. The problem is that the user can still override this with:
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
Is there a way to prevent this case?
Sure.
You can impose that T and TType are the same type
template <Type T = TType,
typename = typename std::enable_if<
std::is_same<T, T1>::value
&& std::is_same<T, TType>::value>::type>
void funcA1() { }
This prevent the template "hijacking".
You can exploit inheritance to provide desired functions. With CRTP, you access functionality of the original class in the func_provider by self pointer.
template<class T, class Derived> struct func_provider;
template<class Derived>
struct func_provider<int, Derived> {
void funcA1() {
auto self = static_cast<Derived*>(this);
// do something with self
}
};
template<class Derived> struct func_provider<double, Derived> { void funcA2() {} };
template<class T>
struct foo : public func_provider<T, foo<T>> {};
int main() {
foo<int> f;
foo<double> g;
f.funcA1();
// f.funcA2(); // Error
g.funcA2();
// g.funcA1(); // Error
}
EDIT:
This version allows the user to implement function for multiple types in one place, user can combine types together:
template<class... Ts> struct types {};
template<class Types, class T> struct is_in : public std::false_type {};
template<class... Ts, class T>
struct is_in<types<T, Ts...>, T> : public std::true_type {};
template<class... Ts, class T0, class T>
struct is_in<types<T0, Ts...>, T> : public is_in<types<Ts...>, T> {};
template<class Derived, bool B, class T> struct func_provider {};
template<class Derived, class T, class... Ts>
struct func_collector
: public func_provider<Derived, is_in<Ts, T>::value, Ts>...
{};
// implement functions for int
template<class Derived>
struct func_provider<Derived, true, types<int>> {
void funcA1() {
auto self = static_cast<Derived*>(this);
// do something with self
}
};
// implement functions for double
template<class Derived>
struct func_provider<Derived, true, types<double>> { void funcA2() {} };
// implement functions for both int and double
template<class Derived>
struct func_provider<Derived, true, types<int, double>> { void funcA1_2() {} };
template<class T>
struct foo : public func_collector<foo<T>, T,
// pull desired functions
types<int>, types<double>, types<int, double>>
{
void common() {}
};
int main() {
foo<int> f;
foo<double> g;
f.common();
f.funcA1();
f.funcA1_2();
// f.funcA2(); // Error
g.funcA2();
g.funcA1_2();
// g.funcA1(); // Error
}
Solution 1
One way to achieve what you ask for is to use tempalte specialization and dependent base classes to offer the optional functionalities.
// I'm using E for enum. I find TType a bit misleading, since T usually stands for Type
template< Type EType >
struct VarApiBase { }; // empty by default
template< >
struct VarApiBase<T1> {
void funcA1() { }
};
template< >
struct VarApiBase<T2> {
void funcA2() { }
};
template <Type TType>
struct VarApi : VarApiBase<TType> {
void funcA1_2() { }
};
template <>
struct VarApi<T3> { };
I'm not particularly fond of this solution. Because it becomes complex to provide shared functions (I put funcA1_2 in VarApi, and not in the base, and then specialized VarApi again to disable it for T3, but this is forcing you to explicitly specialize every time you add a new EType value. You could get around it with an enabler for the specialization, but it again become complex if you have more intricate sharing).
If you need it, you can give VarApiBase access to VarApi by declaring it a friend in VarApi.
Solution 2
As a cheap alternative to all of this, you may just add a static_assert inside your functions:
template <Type ETypeInner = EType >
void funcA1_2() {
static_assert(ETypeInner==EType);
static_assert(EType == T1 || EType == T2);
}
If you really need SFINAE, you can still put the ==T1 || ==T2 condition in the template
template <Type ETypeInner = EType,
typename = typename std::enable_if<ETypeInner == T1 || ETypeInner == T2>::type >
void funcA1_2() {
static_assert(ETypeInner==EType);
}
but be aware it will make compilation slower.
Solution 3
Probably, the cleanest way would be to have explicit specializations and utility functions.
In VarApi.h:
struct VarApiImpl;
template< Type EType >
struct VarApi; // undefined
// Ideally, VarApiCommon shouldn't need to be a template
template< Type EType >
struct VarApiCommon {
// you can put here members and functions which common to all implementations, just for convenience.
void common() { /* ... */ }
private:
// You can do this if you need access to specialization-specific members.
// Ideally, if a function is common, it should only need common members, though.
VarApi<EType> & Derived() { return static_cast<VarApi<EType>&>(*this); }
VarApi<EType> const& Derived() const { return static_cast<VarApi<EType> const&>(*this); }
};
template<>
struct VarApi<T1> : VarApiCommon<T1> {
friend VarApiImpl;
friend VarApiCommon<T1>;
void funcA1();
void funcA1_2();
};
template<>
struct VarApi<T2> : VarApiCommon<T2> {
friend VarApiImpl;
friend VarApiCommon<T2>;
void funcA2();
void funcA1_2();
};
template<>
struct VarApi<T3> : VarApiCommon<T3> {
friend VarApiCommon<T3>;
};
In VarApi.cpp:
struct VarApiImpl final {
// Here go the functions which are only shared by some specializations
template< Type EType >
static void funcA1_2(VarApi<EType>& vapi) {
// Just for sanity. Since this function is private to the .cpp, it should be impossible to call it inappropriately
static_assert(EType==T1 || EType==T2);
// ...
}
};
void VarApi<T1>::funcA1() { /* ... */ }
void VarApi<T1>::funcA1_2() { VarApiImpl::funcA1_2(*this); }
void VarApi<T2>::funcA2() { /* ... */ }
void VarApi<T2>::funcA1_2() { VarApiImpl::funcA1_2(*this); }
It gets as verbose as C++ can be, but at least you have explicit interfaces clearly stating what's offered and what's not, without having to read a bunch of enable_ifs.
Solution 4
Ultimately, I would suggest you to look more carefully at your requirements, to see if they can't be expressed as a proper class hierarchy, based on the features each enum value represents. C++ even has virtual inheritance, if you need to avoid duplicate bases. For instance, that'd be possible in your example:
struct VarApiCommon {
void common();
};
struct VarApi12 : VarApiCommon {
void funcA1_2();
};
template< Type EType >
struct VarApi; // undefined
template<>
struct VarApi<T1> : VarApi12 {
void funcA1();
};
template<>
struct VarApi<T2> : VarApi12 {
void funcA2();
};
template<>
struct VarApi<T2> : VarApiCommon {
void funcA3();
};
If you had a funcA2_3, for instance, you may still be able to do it this way:
struct VarApiCommon {
void common();
};
struct VarApi12 : virtual VarApiCommon {
void funcA1_2();
};
struct VarApi23 : virtual VarApiCommon {
void funcA2_3();
};
template< Type EType >
struct VarApi; // undefined
template<>
struct VarApi<T1> : VarApi12 {
void funcA1();
};
template<>
struct VarApi<T2> : VarApi12, VarApi23 {
void funcA2();
};
template<>
struct VarApi<T2> : VarApi23 {
void funcA3();
};
Much depends on the members.
My suggestion is based on you being able to provide the implementation, but wanting to hide it.
Have a base implementation, which implements everything
template <class X> class Base
{
public:
void A();
void B();
void C();
void D();
void E();
};
Have a derived class which inherits protected, but then publishes public all the common methods from the base
template <class X> class Mid: protected Base<X>
{
public:
using Base::A;
using Base::B;
using Base::C;
// D & E are contentious
};
Have the actual published class, where each variant T1, T2, T3 is specialised.
These classes all publicly inherit from the second class, but then public friend publish the methods they do support.
template <class X> class Top: public Mid<X> {};
template <> class Top<X1>: public Mid<X1>
{
public:
using Base::D;
// Can't get E
};
template <> class Top<X2>: public Mid<X2>
{
public:
// Can't get D
using Base::E;
};
Gains: The methods you want to hide are not accessible. There is no template function magic.
Losses: The rules for publishing are arbitrary, and not driven by 'readable' FINAE at all. You also can't easily use inheritance to build rules either, though you might be able to do a LikeX second template argument.

Get typename from passed in template

Is it possible to get the typename off a template that is passed into another template? Here is a basic example of what the goal is
#include <memory>
#include <string>
#include <iostream>
class IntId {
private:
int id;
public:
IntId(int id) {
this->id = id;
}
};
class StringId {
private:
std::string id;
public:
StringId(std::string id) {
this->id = id;
}
};
template<typename T_Id>
class Object : public std::enable_shared_from_this<Object<T_Id>>
{
private:
T_Id id;
public:
typedef T_Id T;
Object(T_Id id) {
this->id = id;
}
T_Id getId()
{
return this->id;
}
};
template <class T, class Enable = void>
class Observable {
public:
// Intentionally doesn't have a set so it breaks the build... I want both types to go into the value below
void setNonSpecialized(T value) {
}
};
template<typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<IntId>, T>::value>::type> {
private:
std::shared_ptr<T> value;
public:
Observable() {
value = nullptr;
};
void set(std::shared_ptr<T> newValue) {
this->value = newValue;
}
};
class UPCObject : public Object<IntId> {
};
class UserObject : public Object<StringId> {
};
int main()
{
auto upcObject = std::make_shared<UPCObject>();
auto upcObservable = std::make_shared<Observable<UPCObject>>();
upcObservable->set(upcObject); // Expected to succeed as UPCObject inherits from Object<IntId> which matches template
auto userObject = std::make_shared<UserObject>();
auto userObservable = std::make_shared<Observable<UserObject>>();
userObservable->set(userObject); // Want this to succeed as UserObject inherits from Object<StringId> which would match template Object<T::T_Id>
auto intObservable = std::make_shared<Observable<int>>();
intObservable->setNonSpecialized(0); // Expected to succeed and use the value on non-specialized Observable
return 0;
}
In the code above, upcObject succeeds in it's build because it's type matches the templated type. UserObject doesn't because it has a different Id type.
Now if I change the specialization to the following and explicitly describe the type
template <typename T, typename T_Id>
class Observable<T, typename std::enable_if<std::is_base_of<Object<T_Id>, T>::value>::type>
I get the build error 'T_Id': template parameter not used or deducible in partial specialization 'Observable<T,std::enable_if<std::is_base_of<Object<T_Id>,T>::value,void>::type>' because T_Id isn't actually used in Observable at all.
What would be great is if I could do something like the following
template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<T::T_Id>, T>::value>::type>
Where I am able to get the T_Id off the type being passed in. Because in this specialization I'm checking the base of Object, it should have a type defined on it.
In your case, since you define a typedef in the Object class, you can simply do this:
template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<typename T::T>, T>::value>::type>
If you were not using that typedef, you could do that:
// returning a pointer protect us from abstract types.
template<typename T>
T* get_object_type(const Object<T>&);
template<typename T>
using object_type_t = typename std::remove_pointer<
decltype(get_object_type(std::declval<const T&>()))
>::type;
And then, use the type trait:
template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<object_type_t<T>, T>::value>::type>
Note that sfinae will occur first on object_type_t. If the function get_object_type is not callable using a const T&, that specialization of Observable will be ruled out. If T don't extends Object<T>, but the function get_object_type is still callable, then your condition with is_base_of will rule out the specialization of Observable.

Disable functions inside templated class

I'm trying to disable some functions inside a simple template class. The functions that should be removed depend on whether the template argument has certain typedefs.
The example boils down to this:
template<typename T>
struct Foo
{
typename T::Nested foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}
However this gives me a error: no type named ‘Nested’ in ‘struct NoNested’ style error on gcc and clang++ (mind you old versions of both).
Is there an easy way to remove foo when the typedef T::Nested does not exit? (Other than template specialization of the Foo<T> class, as in the real code I have this for about 5 functions with different typedefs.. which would result in 2^5 different specialization )
EDIT:
Since there has been some asking for the motivation for wanting to do this:
I'd like to create something like acompile time FSM for use in a DSL.
I'd like to be able to do this
struct StateA;
struct StateB;
struct StateC;
struct StateA
{
typedef StateB AfterNext;
};
struct StateB
{
typedef StateA AfterPrev;
typedef StateC AfterNext;
};
struct StateC
{
typedef StateB AfterPrev;
};
template<typename T>
struct FSM
{
FSM<typename T::AfterNext> next() { return FSM<T::AfterNext>(); };
FSM<typename T::AfterPrev> prev() { return FSM<T::AfterPrev>(); };
};
So that
FSM<StateA>().next().prev().next().next();
compiles, but
FSM<StateA>().next().prev().prev();
fails.
Note that in reality there would be more transition functions than this, the transition functions would actually do something, and the FSM would store some state.
UPDATE:
I've created proper examples using the methods that have been given so far.
The answers vary in complexity, and while visitors method is the one I'd probably end up using (as it is simplest), my solution (the most complicated) is the only one that actually removes the function.
You can use class template specialization. If you have several functions, then you can move each function to a base class, and specialize each base class.
Try making function foo template itself. It will compile only when called, so you will get the error only when you will try calling it with NoNested class.
You could add a nested typedef to every class, such that compilation only fails when the function is instantiated.
struct null_type; //an incomplete type, you could use a more descriptive name for your particular problem
template<typename T>
struct Foo
{
typename T::Nested foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
typedef null_type Nested;
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo(); //attempt to use incomplete type when used
fnn.bar();
}
It is possible to choose the type T::Nested, if it exists, otherwise void, as follows.
The default choice is void:
template<class T, class = void>
struct NestedReturn
{
typedef void type;
};
A template which always returns void, whatever type you give it:
template<class T>
struct Void
{
typedef void type;
};
A specialisation for types with a Nested nested class by SFINAE. Note that typename Void<typename T::Nested>::type is always void, to match the default second parameter of void in the base template:
template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
typedef typename T::Nested type;
};
And now we use it. Note that foo() is not actually removed when there is no T::Nested, but instantiating it causes an error.
template<typename T>
struct Foo
{
typename NestedReturn<T>::type foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}
I suspect that using default function template parameters it would be possible to remove foo() properly using SFINAE, but that's only possible in C++11 (untested guesswork):
template<typename T>
struct Foo
{
template<class N = T::Nested>
N foo() { return N(); }
int bar() { return 1; }
};
Here's how I think I can solve it. It's inspired by user763305's comments.
It requires 2*N specialisations rather than 2^N.
template <typename T>
struct has_nested {
// Variables "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(typename C::Nested*);
template <typename>
static no& test(...);
// If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
// the first overload worked and T has a nested type named type.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template<typename T>
struct FooBase
{
int bar() { return 1; }
};
template<typename T, bool>
struct FooImpl : public FooBase<T>
{
};
template<typename T>
struct FooImpl<T,true> : public FooBase<T>
{
typename T::Nested foo() { return typename T::Nested(); }
};
template<typename T>
struct Foo : public FooImpl<T, has_nested<T>::value >
{
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}