std::enable_if, template specialization

Started by
14 comments, last by CodeCriminal 11 years, 7 months ago


You could try changing the specialization to:

template <> typename std::enable_if<std::is_arithmetic<mytype>::value, mytype>::type func(const mytype& x) noexcept;



I could try this but it would involve specializing is_arithmetic for mytype which is something I don't really want to do. Even still it would only evaluate to true and produce the same problems.
[/quote]

I really doubt you're going to be able to specialize the function if your type doesn't have is_arithmetic<mytype>::value==true . You are allowed to specialize templates in the standard library (under certain conditions). The following code compiles even though the mytype specialization of func doesn't use is_arithmetic:


#include <iostream>
#include <type_traits>
// firstsomething.hpp
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type func(const T& x) noexcept
{ return x; }
// something.hpp
class mytype {
};
namespace std {
template<> class is_arithmetic<mytype> {
static const bool value=1;
};
}
template <> mytype func(const mytype& x) noexcept { return mytype(); }
int main() {
func(0.0);
func(0);
}


If the is_arithmetic specialization was removed, the code would fail to compile on GCC 4.6. If your type is not an arithmetic type then I think you're going to have to use function overloading.

I think I was concerned that creating an overload would break func for integer types because mytype does not have an explicit constructor and it still takes a single argument integer value. However this is not the case apparently.[/quote]
Yes; the compiler will prefer to instantiate a template over having a cast and using a non-template (although you can force it to use the non-template version by generating a function pointer to it and calling it, or you can force it to use a template by specifying the template arguments explicitly).
Advertisement

[quote name='roadysix' timestamp='1346540294' post='4975578']
I could probably cast the non-const pointer to const but this isn't really desirable.

Overloading to the rescue (how ironic...):

template <typename T> void function(T x)
{ ... }

template <typename T> void function(const T* x)
{ ... }

template <typename T> void function(T* x)
{ function(static_cast<const T *>(x)); }

[/quote]

Incurring the overhead of a proxy function call is also undesirable, where simply being able to partially specialize a function would be favourable.
Alas, as pointed out it is not possible.


[quote name='roadysix' timestamp='1346540294' post='4975578']
Of course, these are all hypothetical needs, and I don't imagine I will come across anything like this in the near future, if ever, though it is still interesting and worth knowing.

Perhaps not in a near future, but they certainly aren't hypothetical. I would say that your example with just an overload for pointer type is a fairly trivial and not totally unexpected example....
[/quote]

Hmm well I would still try to avoid this kind of thing some way or another.



[quote name='roadysix' timestamp='1346530306' post='4975525']

You could try changing the specialization to:

template <> typename std::enable_if<std::is_arithmetic<mytype>::value, mytype>::type func(const mytype& x) noexcept;


I could try this but it would involve specializing is_arithmetic for mytype which is something I don't really want to do. Even still it would only evaluate to true and produce the same problems.
[/quote]
I really doubt you're going to be able to specialize the function if your type doesn't have is_arithmetic<mytype>::value==true . You are allowed to specialize templates in the standard library (under certain conditions). The following code compiles even though the mytype specialization of func doesn't use is_arithmetic:
[/quote]

I soon realized this after posting that reply and decided to go with the function overload. Extending the standard namespace is something I try to avoid, but I am interested in what these "certain conditions" are, if you could explain further.

Incurring the overhead of a proxy function call is also undesirable

Any decent compiler will remove the extra function call.

[quote name='roadysix' timestamp='1346542823' post='4975590']
Incurring the overhead of a proxy function call is also undesirable

Any decent compiler will remove the extra function call.
[/quote]

Oh, thats good to know :) makes sense really

I soon realized this after posting that reply and decided to go with the function overload. Extending the standard namespace is something I try to avoid, but I am interested in what these "certain conditions" are, if you could explain further.


This is what the standard says about it (this is from a 2005 draft but I doubt the C++11 standard changed this significantly):

"It is unde?ned for a C++ program to add declarations or de?nitions to namespace std or namespaces within names-
pace std unless otherwise speci?ed. A program may add template specializations for any standard library template to
namespace std. Such a specialization (complete or partial) of a standard library template results in unde?ned behavior
unless the declaration depends on a user-de?ned type of external linkage and unless the specialization meets the standard
library requirements for the original template.
171)
A program may explicitly instantiate any templates in the standard
library only if the declaration depends on the name of a user-de?ned type of external linkage and the instantiation meets
the standard library requirements for the original template."

Footnote 171: "Any library code that instantiates other library templates must be prepared to work adequately with any user-supplied specialization that meets
the minimum requirements of the Standard."

You might want to wait for concepts to be standardized (or killed) before trying to add information about when a template would work to its interface. You're going to have to change your code if the standards comittee actually implements concepts and you want to use that feature (which would basically do what you're trying to do right now).
http://en.wikipedia.org/wiki/Concepts_%28C%2B%2B%29
However, this probably isn't going to be standardized for another 5 years at least (if it does become standard).

You might want to wait for concepts to be standardized (or killed) before trying to add information about when a template would work to its interface. You're going to have to change your code if the standards comittee actually implements concepts and you want to use that feature (which would basically do what you're trying to do right now).
http://en.wikipedia..../Concepts_(C++)
However, this probably isn't going to be standardized for another 5 years at least (if it does become standard).


I had heard about concepts some time ago, though it is only now that I need them that I understand what they are for ("concepts" is a bit misleading), but as you said I'd be waiting a long time for them to implemented, (if the implementation of the c++11 standard is anything to go by) anyway thanks for clarifying and I think I'll stick with the regular function overload for now :)

This topic is closed to new replies.

Advertisement