Function template partial specialization - are there any workaround? - c++

I have the following function
enum class NodeCachingOptions
{
AddPath,
DontAddPath
};
template <typename T, NodeCachingOptions>
T* CreateSObject(const MPath& path)
Idea was to specialize function for different NodeCachingOptions.
Turned out it is impossible to use partial function template specialization, thus I tried a workaround:
template <typename T, NodeCachingOptions>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<class T, NodeCachingOptions> temp
return temp.call(ob);
}
template <typename T, NodeCachingOptions>
struct CreateSObject_Impl
{
T* call(const MPath& ob);
};
template <typename T>
struct CreateSObject_Impl<typename T, NodeCachingOptions::AddPath>
{
T* call(const MDagPath& ob)
{…}
}
template <typename T>
struct CreateSObject_Impl<typename T, NodeCachingOptions::DontAddPath>
{…}
However I'm getting compile error: ::NodeCachingOptions': illegal type for non-type template parameter '__formal'
What am I doing wrong and is there a better way to solve this problem?
I took idea of struct impl from here: Partial template specialization of free functions - best practices

Your syntax is all wrong. Make it
template <typename T, NodeCachingOptions opt>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<T, opt> temp;
return temp.call(ob);
}
You pass the value of type NodeCachingOptions as the second template paramter of CreateSObject_Impl, not the type itself.
You may want to make call a static member of CreateSObject_Impl, and write return CreateSObject_Impl<T, opt>::call(ob);

Related

Specialization template class with templated function

I have some helper template with templated function. I'm using it for other policy-based templated class to cast or not to cast some value to specific type:
// use this when needed additional value cast
template <typename T>
struct AdditionalValueStaticCaster
{
template <typename U>
static T cast(U u)
{
return static_cast<T>(u);
}
};
// use this specialization when no needed to cast value
template <>
struct AdditionalValueStaticCaster<void>
{
template <typename U>
static U cast(U u)
{
return u;
}
};
Now I want to split these classes to declaration and implementation (.h and .hh files)
So I write declaration like this:
template <typename T>
struct AdditionalValueStaticCaster
{
template <typename U>
static T cast(U u);
};
template <>
struct AdditionalValueStaticCaster<void>
{
template <typename U>
static U cast(U u);
};
And now I want to write implementation. This is ok:
template <typename T>
template <typename U>
T AdditionalValueStaticCaster<T>::cast(U u)
{
return static_cast<T>(u);
}
But this causes error error: too many template-parameter-lists
template<>
template <typename U>
U AdditionalValueStaticCaster<void>::cast(U u)
{
return u;
}
If I delete line template<> all compiles ok, but I still have a question: is it right solution or I missed something?
If I delete line template<> all compiles ok, but I still has question: is it right solution or I missed something?
That's correct, you just need to delete that line. AdditionalValueStaticCaster<void> is a concrete type and you're just providing the definition of a member function template on that type. Hence:
template <typename U>
U AdditionalValueStaticCaster<void>::cast(U u)
{
return u;
}
No different than the member function template on any other class type:
template <typename U>
U SomeClass::cast(U u)
{
return u;
}
I don't think that you can define a template with in a template.
put all the template parameters in the first template line. like this.
template <typename T, typename U>
struct AdditionalValueStaticCaster
{
static T cast(U u)
{
return static_cast<T>(u);
}
};
specialized to an actual object like this:
AdditionalValueStaticCaster< My_T_Type, My_U_Type> MyNewCaster;
and used like this
My_T_Type My_T_Type_var;
My_U_Type My_U_Type_var;
My_T_Type_var = MyNewCaster.cast(My_U_Type_var);
Sorry I don't have a compiler to check this on, but syntax should be close.

deducing a tuple's types

I have code something like this:
template <typename T>
inline typename ::std::enable_if<
is_std_tuple<T>{},
T
>::type
get()
{
// pull tuple's elements from somewhere
}
In order to deduce the template type parameters the tuple was instantiated with, I did this casting:
static_cast<T*>(nullptr)
and pass this as a parameter to a function
template <typename ...A>
void deduce_tuple(::std::tuple<A...>* const);
Am I committing UB? Is there a better way?
The imperfection here is that we cannot partially specialize function templates. Your way is fine, since we're not dereferencing the null pointer; I'd prefer using a designated tag:
template <typename...> struct deduction_tag {};
template <typename... Ts>
std::tuple<Ts...> get(deduction_tag<std::tuple<Ts...>>) {
// […]
}
template <typename T>
std::enable_if_t<is_std_tuple<T>{}, T> get() {
return get(deduction_tag<T>{});
}

C++ enable_if in class - different ways of destruction

I am developing an application for an embedded device and therefore I do not have type_traits and enable_if (poor compiler quality). I created them on my own:
template <typename T>
struct is_pointer_t{
enum{value = false};
};
template <typename T>
struct is_pointer_t<T*>{
enum{value = true};
};
and simillar declarations for consts and volatiles.
Now implementation of enable_if:
template <bool boolean, typename T = void>
struct enable_if{};
template <typename T>
struct enable_if<true, T>{
typedef T type;
};
Now I want to have a class, that depeneding on wheather I use pointers or normal types it calls destructor on them or not, so it would be great if I could have templated destructor. But I do not know how to do this as I am just beginning to undestand template programming. Following attempts failed:
template <typename T>
class pointerOrNot{
public:
template <typename U>
void one();
};
template <typename T>
template <typename enable_if<is_pointer_t<T>::value>::type>
void pointerOrNot<T>::one(){
std::cout << "Success1" << std::endl;
}
template <typename T>
template <typename enable_if<!is_pointer_t<T>::value>::type>
void pointerOrNot<T>::one(){
std::cout << "Success2" << std::endl;
}
and it says it does not match definition. So I tried following:
template <typename T>
class pointerOrNot{
public:
template <typename enable_if<is_pointer_t<T>::value>::type>
void one();
template <typename enable_if<!is_pointer_t<T>::value>::type>
void one();
};
But then one of one() has empty type as template and compilation fails. How can I do this? Also is it possible to do this with destructor?
First lets consider the following class for pointers:
template <typename T>
struct Introducer{
void intro(){
std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
}
T mem;
Introducer(T m):mem(m){}
};
it works fine with pointers, but it also works with non-pointers:
Introducer<int> i(10);
i.intro();//just fine!
We would like to detect this misuse during the compile time, also we change Introducer to
template <typename T>
struct Introducer{
typename enable_if<is_pointer_t<T>::value, void>::type //this is the return type of the function
intro(){
std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
}
...
};
Now compiler does not allow us to use non-pointer with Introducer. In the next step we would like to have a special function for non-pointers by means of SFINAE:
template <typename T>
struct Introducer{
typename enable_if<is_pointer_t<T>::value, void>::type
intro(){
std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
}
typename enable_if<!is_pointer_t<T>::value, void>::type
intro(){
std::cout<<"I'm a non-pointer, my value is "<<mem<<std::endl;
}
...
};
Hell, it does not even compile! Lets read the passage about SFINAE more carefully:
If a substitution results in an invalid type or expression, type
deduction fails. An invalid type or expression is one that would be
ill-formed if written using the substituted arguments. Only invalid
types and expressions in the immediate context of the function type
and its template parameter types can result in a deduction failure.
T is not in the immediate context and thus SFINAE doesn't work, lets bring T into the immediate context:
template <typename T>
struct Introducer{
template <typename C=T>
typename enable_if<is_pointer_t<C>::value, void>::type
intro(){
std::cout<<"I'm a pointer, I point to adress "<<mem<<std::endl;
}
template <typename C=T>
typename enable_if<!is_pointer_t<C>::value, void>::type
intro(){
std::cout<<"I'm a non-pointer, my value is "<<mem<<std::endl;
}
...
};
now the program
int main(){
Introducer<float*> fp(NULL);
fp.intro();
//But this works also:
Introducer<int> i(10);
i.intro();
}
results in:
I'm a pointer, I point to adress 0
I'm a non-pointer, my value is 10
What about the destructor? The easiest way would be to call a SFINAE-destruction-function from the destructor (I never saw a SFINAE-destructor and would not know how to write one, but this doesn't mean anything):
template <typename T>
struct Introducer{
...
~Introducer(){
intro();
std::cout<<"and I'm deleted..."<<std::endl;
}
};

Template friend function of template class that introduces a new template parameter

Thanks to Daniel Frey's answer to this post, I know how to declare a template friend function to a template class with the same template parameters. Unfortunately, the syntax for declaring a friend function with additional template parameters still escapes me. I would like to achieve something like this:
template <typename T>
class Obj;
template <typename T>
Obj<T> make_obj(T t);
template <typename T, typename RetVal>
RetVal ret_obj(T t);
template <typename T>
class Obj {
private:
T & t;
Obj (T & t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
template <typename RetVal>
friend RetVal ret_obj<T, RetVal>(T t);
};
template <typename T>
Obj<T> make_obj(T t) {
return Obj<T>(t);
}
template <typename T, typename RetVal>
RetVal ret_obj(T t) {
return RetVal(make_obj(t).t);
}
I know that the same question has already been asked in this post, but the accepted answer there does not seem to be what I want: changing the parameter name to T2 makes the function a friend of all specializations of the object, while I want to keep T the same as in the class.
It is impossible to let friend declarations refer to partial specializations - either they refer to a specific specialization or to the primary template. Moreover, function templates cannot be partially specialized anyway.
What is not possible with function templates is often doable using class templates though:
template <typename T>
struct ret_obj_helper {
// Here goes the original definition of ret_obj - the important difference
// is the location of the template parameter T, which is the one
// fixed by the friend declaration below
template <typename RetVal>
RetVal ret_obj(T t) {return RetVal(make_obj(t).t);}
};
// I guess RetVal, having to be explicitly specified, better goes first (?)
template <typename RetVal, typename T>
RetVal ret_obj(T&& t)
{
// Overcomplicated for the sake of perfect forwarding
return ret_obj_helper<typename std::remove_reference<T>::type>{}.
template ret_obj<RetVal>(std::forward<T>(t));
}
template <typename T>
class Obj {
private:
T t;
Obj (T t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
// Make all specializations of the member function template
// of ret_obj_helper<T> a friend, regardless of the return type
template <typename RetVal>
friend RetVal ret_obj_helper<T>::ret_obj(T t);
};
Demo.

Specialize a template with a template

I have a (free) function template that looks like this
template <typename T>
T get();
I now want to specialize this function for a class, which itself is a template. But my compiler doesn't want to compile it, and I'm asking now if that is even possible and how I could achieve it. Just for the idea, the code could look as follows: (Doesn't compile)
template <>
template <typename T>
foo_type<T> get<foo_type<T>>()
What you're doing is called partial specialization of function template. But partial specialization of function template is not allowed. Overloading of function template is allowed, but in this case, it is not possible either, as the function has only return type, and overloading on return type is not allowed.
So the solution is this:
namespace details
{
template <typename T>
struct worker
{
static T get();
};
template <typename T> //partial specialization of class is allowed
struct worker<foo<T>>
{
static foo<T> get();
};
}
template <typename T>
T get()
{
return details::worker<T>::get();
}
You could also use overloads if you define them to take one argument so as to make overload valid:
namespace details
{
template <typename T>
static T get(T*);
template <typename T>
static foo<T> get(foo<T>*); //now the overload is valid
}
template <typename T>
T get()
{
return details::get<T>(static_cast<T*>(0));
}
Note that the argument static_cast<T*>(0) is used to help the compiler to select the correct overload. If T is other than foo<U>, then the first overload will be selected as the type of the argument passed to it will be T* as opposed to foo<U>*. If T is foo<U>, then the second overload will be selected by the compiler because it is more specialized, and can accept the argument passed to it which is foo<U>* in this case.
As Nawaz said, the standard just doesn't allow you to do that. You could however extract the implementation into the static method of a class and partially specialize that class.
template<class T>
struct get_impl{
static T get(){ ... }
};
template<class T>
struct get_impl<foo_type<T> >{
static foo_type<T> get(){ ... }
};
template<class T>
T get(){ return get_impl<T>::get(); }