Look at the following test code:
template<class T> struct Wrap {};
template<typename T> inline
void fun (T *&Int) // **choice 1**
{}
template<typename T> inline
void fun (Wrap<T> *&Int) // **choice 2**
{}
int main()
{
int i = 6;
fun((char*&)(i)); // **call 1**
fun((Wrap<char>*&)(i)); // **call 2**
}
When I run this code in linux g++, it works as per expectations. When fun() is called with char*&, it calls function of choice 1 straight forward.
However, I am interested when we call fun() with Wrap< char >*& and it calls the choice 2. Even though choice 1 and 2 both appear valid for the 2nd call, compiler manages to choose little better contender -> choice 2 (because it exists).
Question: Is it guaranteed that, the same behavior will be retained for any other compiler for C++ ? If not, then is there any other alternative to make it deterministic?
The second choice is chosen because it's more specialized than the first- that is, T*& can bind to any non-temporary T*, but Wrap<T>*& can only bind to a non-temporary Wrap<T>*. This is Standard as far as I know and should be portable behaviour but what is and isn't portable in practice when it comes to this sort of thing is often not the definition of what's Standard.
Someone with a better knowledge of the spec can confirm this, but I believe that as Wrap<T> is a more specific type than simply T, call 2 will always resolve to 'choice 2', on all platforms compilers.
While the code might look like a template specialization, that is not the case. The language does not allow for partial template function specializations. The two are unrelated templates that happen to be overloads.
The compiler will lookup up the call to fun( (Wrap<char>*&) i ) with the usual lookup mechanisms, will find the two templates and will determine that there are two potential overloads:
template <typename T> void fun( T*& ); // with T == Wrap<char>
template <typename T> void fun( Wrap<T>*& ) // with T == char
Overload resolution will then determine that the second is a better match and instantiate it. This is guaranteed by the standard, but beware: they are not the same template, but rather different templates and you might run into undexpected results. Look at the article #LiKao linked for more insight.
One thing that might make this even more problematic is, that the rules for specializing template classes and template functions differ a lot. This is do to the possibility of overloading template functions while there is no possibility of overloading classes. Because I am not so firm on this topic I will just link to someone who is able to explain it in more depth:
Herb Sutter: "Why Not Specialize Function Templates?"
Related
I understand that with concepts, a constrained function (regardless how "loose" the constraint actually is) is always a better match than an unconstrained function. But is there any syntax to selectively call the unconstrained version of f() as in the sample code below? If not, would it be a good idea for compilers to warn about uncallable functions?
#include <iostream>
template <typename T> requires(true)
void f() { std::cout << "Constrained\n"; }
template <typename T>
void f() { std::cout << "NOT Constrained\n"; }
int main() {
f<int>();
}
https://godbolt.org/z/n164aTvd3
Different overloads of a function are meant to all do the same thing. They may do it in different ways or on different kinds of objects, but at a conceptual level, all overloads of a function are supposed to do the same thing.
This includes constrained functions. By putting a constrained overload in a function overload set, you are declaring that this is a valid alternative method for doing what that overload set does. As such, if the constraint matches, then that's the function that should be called. Just like for parameters of different types in regular function overloading.
If you want to explicitly call an overload hidden by a constraint, you have already done something wrong in your design. Or more specifically, if some overload is completely hidden by one or more constrained overloads, you clearly have one more overload than you actually needed.
If the constraints match, the caller should be 100% fine with getting the constrained overload. And if this isn't the case, your design has a problem.
So no, there is no mechanism to do this. Just as there's no mechanism to bypass an explicitly specialized template and use the original version if your template arguments match the specialization.
Lets assume I have a template function
template <typename T>
void do_sth(T const&);
For some types ("small" and copyable) it would be better to pass an argument by value instead of reference.
So my question is: What is the simplest way to overload a function depending on the underlying type?
Remark:
Best what I came to is using enable_if with some conditions of "simple" type. And I believe there's no such a type trait as "simple type" in the standard library. Correct me if I'm wrong. Moreover: Using enable_if gets complicated as a function takes more template arguments (edited) because template <typename T, typename U> void do_sth(T, U) would need 4 overloads: (value, value), (value, ref), (ref, value) and (ref, ref).
Don't do this. Template functions are inlined at the drop of a hat, and a reference to an x is an alias with no identity once the function is inlined.
Encourage the function to be inlined instead of doing a mess of SFINAE, unless and until you have proven this to be an important bottleneck.
After discovering this function is taking up more time than anything else you can optimize, test its improvement by manualy writing the by value version in a couple of key cases to ensure you actually get a benefit (I doubt you will).
boost has call_traits:
template <typename T>
void do_sth(typename boost::call_traits<T>::param_type)
But one big issue is that T is no longer deducible
(and so you have to call it do_sth<int>(42) or do_sth<MyBigObj>(myBigObj)).
So might be used for non template methods in template class:
template <typename T>
struct S
{
void do_sth(typename boost::call_traits<T>::param_type);
};
But anyway, chances are that compiler actually inlines code, resulting in same generated code.
struct A
{
template <class U>
void f(U)
{
}
};
template <class T>
void f(T t)
{
A a;
a.template f<int>(t);
a.template f<>(t);
a.f<int>(t);
a.f<>(t);
a.f(t);
}
At least under MSVC2010 the above code compile fine.
Among all the manners to call A.f is there any preferentials way to do this?
Is there any differences ?
Well, a has type A, which is not a dependent type in this context. So the template keyword is not needed and only serves to obfuscate the code -- don't use it.
The version that invokes a template without supplying any arguments, again does nothing to change behavior and only makes the code less readable -- don't use it either.
Between the two remaining candidates, a.f(t) and a.f<int>(t), use the first in most cases, and the second if the compiler fails to deduce the type.
The last one seems easiest to write.
Otherwise there are no differences, unless you have to disambiguate between several f's.
No differences at all. If you don't have any reason to provide type information to the function, the last one is the best. But you may want your function to process arguments as if they are of the specified type, only then, should you need <>. For example
T Divide(T a, T b)
{
return a/b;
}
If you call Divide(5,2), you get 2. Only cases like this, should you specify type:
Divide<float>(5,2);
It returns 2.5.
I unfortunately have several macros left over from the original version of my library that employed some pretty crazy C. In particular, I have a series of macros that expect certain types to be passed to them. Is it possible to do something along the lines of:
static_assert(decltype(retval) == bool);
And how? Are there any clever alternatives?
Yes I'm aware macros are bad. I'm aware C++ is not C, etc.
Update0
Here is some related code, and the source file. Suggestions are welcome. The original question remains the same.
I found this to be the cleanest, using #UncleBens suggestion:
#include <type_traits>
static_assert(std::is_same<decltype(retval), bool>::value, "retval must be bool");
Disclaimer: This is a bad answer, there are definitely far better solutions. Just an example :)
It is bound to be already implemented, but it's trivial to implement yourself;
template <class T1, class T2> struct CheckSameType; //no definition
template <class T> struct CheckSameType<T,T>{}; //
template <class T1, class T2>
AssertHasType(T2)
{
CheckSameType<T1, T2> tmp; //will result in error if T1 is not T2
}
To be used like this:
AssertHasType<bool>(retval);
Alternative (suggested by GMan):
template <class T1, class T2> struct SameType
{
enum{value = false};
}
template <class T> struct SameType<T,T>
{
enum{value = true};
};
To be used like
static_assert(SameType<decltype(retval), bool>::value);
It appears you need decltype because you've got an expression, but want to verify a type. There are already enough ways to do that now (C++03). For instance, to check a bool
inline void mustBeBool(bool) { }
template<typename T> inline void mustBeBool(T t) { & (&t); } // Takes address of rvalue (&t)
// Use:
#define DifficultMacro(B) do { mustBeBool(B); foo(B); } while (false)
If you DO care about the const and volatile qualifiers, and want to ensure the const and volatile parts of the types also exactly match the type you are comparing against, do like #Matt Joiner says:
#include <type_traits>
static_assert(std::is_same<decltype(my_variable), uint64_t>::value,
"type must be `uint64_t`");
I you do NOT care about const, however, and want to simply ensure the type is a certain type without regard for const, do the following instead. Note that std::remove_const<>::type is required here:
static_assert(std::is_same<std::remove_const<decltype(my_variable)>::type, uint64_t>::value,
"type must be `uint64_t` OR `const uint64_t`");
The same goes for volatile. In case you don't care about the volatile part of the type either, you can ignore it with std::remove_volatile<>::type:
static_assert(std::is_same<std::remove_volatile<decltype(my_variable)>::type, uint64_t>::value,
"type must be `uint64_t` OR `volatile uint64_t`");
If you don't care about const OR volatile, you can remove them both with std::remove_cv<>::type:
static_assert(std::is_same<std::remove_cv<decltype(my_variable)>::type, uint64_t>::value,
"type must be `uint64_t` OR `const uint64_t` OR `volatile uint64_t` OR `volatile const uint64_t`");
Note also that as of C++17 you can do:
std::remove_cv_t<decltype(my_variable)> in place of std::remove_cv<decltype(my_variable)>::type, and:
std::is_same_v<some_type, another_type> in place of std::is_same<some_type, another_type>::value.
References:
Use static_assert to check types passed to macro
https://en.cppreference.com/w/cpp/types/is_same
https://en.cppreference.com/w/cpp/language/decltype
https://en.cppreference.com/w/cpp/header/type_traits
https://en.cppreference.com/w/cpp/types/remove_cv - std::remove_cv<>, std::remove_const<>, std::remove_volatile<>
Related:
[another answer of mine where I use the above static_assert tricks] How to make span of spans
Static assert in C [my own answer]
How to use static assert in C to check the types of parameters passed to a macro [my own question]
Typechecking macro arguments in C
*****C++ Limit template type to numbers
Most macros can be replaced with inline functions and/or templates. As a case in point, the overly clever argument-size-checking Posix isnan macro is a template in C++0x. Oh,bad example, but you get the idea.
The main exceptions to that rule are macros that essentially implement higher level language features. For example, smarter exception handling, or covariance, or a parameterized set of declarations.
In some cases the macros that can't be reasonable expressed as inline functions or templates, can be replaced with a smarter kind of preprocessing, namely code generation. Then you have a script somewhere that generates the necessary code. For example, it's possible to do options classes in pure C++ with macros and templates, but it's hairy, and as an easier-to-grok and perhaps more maintainable alternative one might use a script that generates the requisite classes, at the cost of extra build steps and dealing with multiple languages.
Cheers & hth.,
Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.