Suppose, I have a code:
template <typename T>
class C {
public:
T f() { return m_result; }
void todo() { m_result = doit<T>(); }
private:
T m_result;
};
If T is void, I want to return void and have no m_result at all.
But, the compiler does not allow instantiate a void type.
One of decision is to create a specialization.
template <> class C<void> { /* ... */ }
But I don't what to support the almost identical code.
How can I don't instantiate m_result?
I can use C++17. Thanks!
You could place the data in a base class, then use if constexpr:
template<class T>
struct C_data{
T m_result;
};
template<>
struct C_data<void>{
};
template<class T>
class C: C_data<T>
{
static constexpr auto is_void = std::is_same_v<T,void>;
public:
auto f(){
if constexpr(is_void)
return this->m_result;
else
return;
}
void todo(){
if constexpr(is_void)
this->m_result = doit<T>();
else
doit<T>();
}
};
But it can be argued that a the specialization of the class C is cleaner since all member of a template class should depend on all the template parameter (otherwise you should split your class in order to avoid code bloat).
So I would prefer to fully specialize C, and make part of the class C that are independent of T, a base class of C:
class C_base{
//any thing that is independent of T;
};
template<class T>
class C: public C_base{
//any thing that depend on T
};
template<>
class C<void>: public C_base{
//any thing that depend on T;
};
You could also specialize member funtion by member function, but I find it less clean.
You will find this last code structure in almost all headers of standard library implementations.
This works for me:
#include <type_traits>
template <typename T> T doit() { return T{}; }
template <typename T> struct result_policy { T m_result; };
template <> struct result_policy<void> { };
template <typename T>
class C : private result_policy<T> {
public:
T f(){
if constexpr (!std::is_void_v<T>)
return result_policy<T>::m_result;
}
void todo() {
if constexpr(!std::is_void_v<T>)
result_policy<T>::m_result = doit<T>();
}
};
int main() {
C<int> ci;
ci.todo();
int i = ci.f();
C<void> cv;
cv.todo();
cv.f();
}
I used if constexpr from C++17 to work with m_result and stored m_result into policy struct only for non-void types due to partial template specialization.
If you can use C++17, then try with if constexpr, std::is_same_v<> and std::conditional_t<>:
#include <type_traits>
// auxiliary variable template for checking against void type in a more readable way
template<typename T>
constexpr bool is_void_v = std::is_same_v<T, void>;
// auxiliary alias template for determining the type of the data member
// in order to prevent the compiler from creating member of type "void"
// so if T = void --> data member type as "int"
template<typename T>
using member_type_t = std::conditional_t<!is_void_v<T>, T, int>;
template <typename T>
class C{
public:
T f(){ return (T)m_result; } // no problem if T = void
void todo() {
if constexpr(!is_void_v<T>)
m_result = doit<T>();
else
doit<T>();
}
private:
member_type_t<T> m_result;
};
Actually, as of C++17 there is already a std::is_void_v<> variable template with type_traits.
Related
There is a way to make a partial template specialization for a forward-declared (incomplete) type (answer).
But after seeing the mentioned question I wondered if it is possible to define a partial specialization for a class template using an incomplete nested (and possibly private) class.
In C++ currently one can't forward-declare a nested class without defining the class:
class undefined;
class undefined::foo; // impossibru
With some hacks I made a working code (for a sake of research): https://godbolt.org/z/9W8nfhx8P
#include <iostream>
template <typename T, typename = T>
struct specialize;
// workaround to get to a nested foo
template <typename T, typename...>
struct mem_foo
{
// error: 'struct undefined::foo' is private within this context
using type = typename T::foo;
};
class undefined;
// class undefined::foo; // impossibru
template <typename MemFoo>
struct specialize<typename mem_foo<undefined, MemFoo>::type, MemFoo>
{
void operator()(const MemFoo &f) const
{
// this will compile however
std::cout << f.name << std::endl;
}
};
#include <string>
class undefined
{
private: // will not compile without friend
struct foo{
std::string name = "John Cena";
};
friend struct mem_foo<undefined, foo>; // ugly
// friend struct specialize<foo>; // this is irrelevant, but would be nicer than mem_foo
public:
static foo get() { return {}; }
};
int main()
{
specialize</*undefined::foo*/decltype(undefined::get())>{}(undefined::get());
return 0;
}
But for a private types an ugly friend is used. friend struct specialize<undefined::foo>; would be more semantically appealing.
Is there another or more elegant solution?
A more elegant/less convoluted solution: https://godbolt.org/z/3vrfPWP5f
#include <iostream>
template <typename T, typename = T>
struct specialize;
template <typename T, typename ...>
struct defer_instantiation
{
using type = T;
};
template <typename T, typename ... R>
using defer_instantiation_t = typename defer_instantiation<T, R...>::type;
class undefined;
// class undefined::foo; // impossibru
template <typename MemFoo>
struct specialize<typename defer_instantiation_t<undefined, MemFoo>::foo, MemFoo>
{
void operator()(const MemFoo &f) const
{
// this will compile however
std::cout << f.name << std::endl;
}
};
#include <string>
class undefined
{
private:
struct foo{
std::string name = "John Cena";
};
friend struct specialize<foo>; // this is irrelevant, but would be nicer than mem_foo
public:
static foo get() { return {}; }
};
int main()
{
specialize</*undefined::foo*/decltype(undefined::get())>{}(undefined::get());
return 0;
}
It allowes to reference yet non-existing member types of a yet incomplete class via a deferred template instantiation.
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);
}
};
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}
I have a header that forward declares a struct, a function, and defines a template function that uses the struct concrete type:
---header.h
struct RegisterImpl;
RegisterImpl& getRegisterImpl();
template <typename Interface>
void registerModuleClass( .... )
{
RegisterImpl& reg = getRegisterImpl();
reg.data = 3;
...
}
---source.cpp
struct RegisterImpl
{
int data;
};
RegisterImpl& getRegisterImpl()
{
static RegisterImpl instance;
return instance;
}
struct testiFace
{
virtual void Blah() = 0;
};
void useTemplate()
{
registerModuleClass<testiFace>(....);
}
my hope was that instantiation of template function registerModuleClass was going to happen at useTemplate, which happens after the RegisterImpl type is fully defined. But it seems that type resolution of the code is happening at the place where the template definition exists, instead of the instantiation (at the source file)
Am i missing something here? The dilemma here is that the template function needs to use the concrete type of the implementation, but the concrete type happens in the source file. Any way around this?
I'm not sure if this suggestion will help in your situation, but here is an idea: you could wrap the code in a class template that requires RegisterImpl as a template parameter.
Example:
template<typename T>
struct Helper
{
T & getRegisterImpl()
{
static T instance;
return instance;
}
template<typename Interface>
void registerModuleClass()
{
T & reg = getRegisterImpl();
}
};
And later:
struct RegisterImpl
{
int data;
};
Helper<RegisterImpl> helper;
I hope this helps.
Make it depend on the template parameter(s):
template<typename T, typename...> struct depend { typedef T type; };
template <typename Interface>
void registerModuleClass( .... )
{
typedef typename depend<RegisterImpl,Interface>::type LocalRegisterImpl;
LocalRegisterImpl& reg = getRegisterImpl();
reg.data = 3;
...
}
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}