Why the template version is chosen below by the compiler? - c++

The template version is used by the compiler to calculate t = max(a, b) and max(t, c). Any quote from the Standard supporting this is welcome.
#include <iostream>
template <typename T>
inline T const& max (T const& a, T const& b)
{
std::cout << "template" << '\n';
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b, T const& c)
{
return max (max(a,b), c);
}
inline int const& max (int const& a, int const& b)
{
std::cout << "non-template" << '\n';
return a <b ? b : a;
}
int main()
{
std::cout << max(3, 5, 7) << '\n';
}
The code prints
template
template
7

The definition of your non-template version of max() is not visible at the call-site, it's defined afterwards. Either move that function above the 3-argument max() or add a prototype above the call-site.
int const& max (int const& a, int const& b);
Now the non-template version is chosen in both cases.
Live example
As for why this is the case, I believe §3.4.1/1 [basic.lookup.unqual] holds the answer.
In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.
Note that argument-dependent name lookup does not apply in your case since the arguments to max are int, and not a user defined type. Only unqualified name lookup applies, hence, as quoted above, the lookup stops when the first match (the function template version of max()) is found.
The last sentence in the quoted section also explains why if you comment out the function template version of max() your code will not compile.

Related

Three argument function template confusing example

#include <iostream>
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() \n";
return b < a ? a : b;
}
// maximum of three values of any type:
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c); // uses the template version even for ints
} //because the following declaration comes
// too late:
// maximum of two int values:
int max (int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
int main()
{
::max(47,11,33); // OOPS: uses max<T>() instead of max(int,int)
}
In this example (from book noted below) I didnt understand why ::max(47,11,33) call expected to use max(int,int). So one is 2 argument another is 3 argument i think it uses 3 argument function definition as it should.
Am I missing something?
Note: David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor C++ Templates: The Complete Guide [2nd ed.] book
The issue that is being raised is that the non-template overload will not be called.
The max<T>(T a, T b, T c) knows about max<T>(T a, T b) but DOESN'T know that there's an integer overload because it's declared after it.
A solution being: specialize max<T>for T = int rather than define a int(int, int) function:
#include <iostream>
template<typename T>
T max (T a, T b)
{
std::cout << "max<T>() \n";
return b < a ? a : b;
}
template<>
int max (int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c);
}
int main()
{
::max(47,11,33); // BINGO: uses specialized max<int>()
}
Output:
max(int,int)
max(int,int)
This is brittle though, if a non-template function come to use max<int> after max<T> has been defined and before max<int> has been specialized, as per [temp.expl.spec]/6 the program would be ill-formed, no diagnostic required.
If this is a risk you cannot take, there are tools available to you. SFINAE is one of them and could forbid the general max<T> to be called with T = int. This would lead to either a working program or a compilation error.
::max(47, 11, 33); is in fact ::max<int>(47, 11, 33);
which in turns will call ::max<int>(::max<int>(47, 11), 33); which might be surprising.
As intis a built-in (so no ADL), max(int, int) should be visible before max(T, T, T) is defined to permit to call that version in template:
With custom type, thanks to ADL, your max function could be declared after:
template <typename T>
T max (T a, T b)
{
std::cout << "max<T>()\n";
return b < a ? a : b;
}
// Should be declared **before** max(T, T, T)
int max(int a, int b)
{
std::cout << "max(int,int) \n";
return b < a ? a : b;
}
template<typename T>
T max (T a, T b, T c)
{
return max (max(a,b), c);
}
struct S {};
// Might be declared after max(T, T, T)
S max(S, S)
{
std::cout << "max(S, S)\n";
return {};
}
Now, both max(0, 1, 2) and max(s, s, s) would call internally the non template overload.
Demo

C++ noexcept declaration changes template deduction

I was tinkering to confirm the example on page 91 of Effective Modern C++, and I ran into what seems to be a strange issue. This code
template<typename C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {
std::cout << "container version" << std::endl;
}
template<>
void doStuff<int>(int& x, int& y) noexcept {
std::cout << "int version" << std::endl;
}
int main() {
vector<int> v1 = {1, 2, 3};
vector<int> v2 = {4, 5, 6};
int x = 5;
int y = 6;
doStuff(x, y);
doStuff(v1, v2);
}
Gives me an error like
error: request for member ‘front’ in ‘a’, which is of non-class type
‘int’ void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(),
b.front()))) {
So, it seems like the top version of doStuff is being called, even though a.front() and b.front() should be returning references to ints. If I remove all the noexcept declarations from the code, I get the expected output.
This is with gcc 5.4.
What am I doing wrong?
Thanks
The problem is, when the name lookup at this point:
template<typename C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(a.front(), b.front()))) {
// ^^^^^^^
will just find one doStuff(): your function template. The specialization hasn't been declared yet, so it isn't considered.
First thing to do is to simply avoid specializations. They're awkward. But then the real fix would be to stick in an extra empty type solely for argument-dependent lookup purposes. This will add a dependent name to the noexcept lookup that will delay invocation until instantiation:
namespace N {
struct adl { };
void doStuff(adl, int& , int& ) noexcept {
std::cout << "int version" << std::endl;
}
template<typename C>
void doStuff(adl, C& a, C& b) noexcept(noexcept(doStuff(adl{}, a.front(), b.front()))) {
std::cout << "container version" << std::endl;
}
}
template <class C>
void doStuff(C& a, C& b) noexcept(noexcept(doStuff(N::adl{}, a, b)))
{
doStuff(N::adl{}, a, b);
}
Template specializations are not overloads. Your specialization for doStuff<int> is not an overload of doStuff<C>, it is a specialization. So overload resolution doesn't consider it, template instantiation will consider it, if the original is selected by overload resolution. Replace your specialization with an overload (non-template, taking two int&s)
void doStuff(int& a, int& b) noexcept;

GCC 4.9 ambiguous overload template specialization

I'm running into an issue with gcc 4.9.2 (with -std=c++11) not compiling a piece of code with the error message being
call of overloaded 'InsertDataIntoInputMap(int&, boost::shared_ptr&)' is ambiguous
The code does compile with msvc 2013
#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>
struct Proxy
{
typedef std::map<int, int> InputDataMap;
int a;
};
template<class C, class D>
void InsertDataIntoInputMap(
const typename C::InputDataMap::key_type& key,
const D val)
{
std::cout << "Not shared\n";
}
template<class C, class D>
void InsertDataIntoInputMap(
const typename C::InputDataMap::key_type& key,
const boost::shared_ptr<D> val)
{
if (val)
{
std::cout << "Shared\n";
}
}
int main() {
int a;
boost::shared_ptr<double> x(new double(4.5));
InsertDataIntoInputMap<Proxy>(a, x);
}
while the following does actually compile with both gcc and msvc:
#include <iostream>
#include <boost/shared_ptr.hpp>
template<class C, class D>
void InsertDataIntoInputMap(
const C& key,
const D val)
{
std::cout << "Not shared\n";
}
template<class C, class D>
void InsertDataIntoInputMap(
const C& key,
const boost::shared_ptr<D> val)
{
if (val)
{
std::cout << "Shared\n";
}
}
int main() {
int a = 0;
boost::shared_ptr<double> x(new double(4.5));
InsertDataIntoInputMap<int>(a, x);
return 0;
}
I would have thought that the compiler should take the function with the boost::shared_ptr argument in both cases?
This problem can be reduced to an imprecision in partial ordering: Pairs in which no template-parameters appear that are involved in deduction are still considered and compaired. That issue was addressed by CWG #455 and #885 as well.
In your example, overload resolution isn't able to distinguish the overloads. Hence partial ordering is necessary. And partial ordering will try to perform deduction twice, with the parameter type P being typename C::InputDataMap::key_type.
However, that deduction is doomed to fail, since C solely appears in a non-deduced context. I.e. the type from both templates (for that particular pair) is not at least as specialized as the type from the respective other template - and that, in turn, implies that neither of the templates is more specialized than the other.
As noted by #T.C., the resolution of CWG #1391 helps. This part in particular:
Change 14.8.2.4 [temp.deduct.partial] paragraph 4 as follows:
Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A. If a particular P contains no template-parameters that participate in template argument deduction, that P is not used to determine the ordering.
Now, the first parameter pair is entirely ignored in both ways (as the types of C are solely determined from the explicit argument list), and the second overload is found to be more specialized.
A simple alias can make that code work:
#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>
struct Proxy
{
typedef std::map<int, int> InputDataMap;
int a;
};
template<class C, class D, class F = typename C::InputDataMap::key_type>
void InsertDataIntoInputMap(
const F& key,
const D val)
{
std::cout << "Not shared\n";
}
template<class C, class D, class F = typename C::InputDataMap::key_type>
void InsertDataIntoInputMap(
const F& key,
const boost::shared_ptr<D> val)
{
if (val)
{
std::cout << "Shared\n";
}
}
int main() {
int a;
boost::shared_ptr<double> x(new double(4.5));
InsertDataIntoInputMap<Proxy>(a, x);
}
But imo. this shouldn't work, cause I thought, the draft says, the compiler will not consider the C::InputDataMap - Namespace in
class F = typename C::InputDataMap::key_type
and F will be a non-deduced context (like key_type).

Template func and non template func call order

In Linux I get
template max() is called
But under Windows I get
non-template max() is called
Why? In Linux, I use gcc 4.5 and in Windows I use VS2008.
#include <iostream>
#include <vector>
template < typename T >
inline void max( const int& a, const T& b )
{
std::cout << "template max() is called" << std::endl;
}
template < typename T >
inline void Imax( const int& a, const std::vector<T>& b)
{
max(a, b[0]);
}
inline void max( const int& a, const int& b )
{
std::cout << "non-template max() is called" << std::endl;
}
int main()
{
std::vector<int> v;
v.push_back(1);
Imax(1, v);
return 0;
}
In pre-standard C++, you would likely get the non-template max.
(Without a standard, it's hard to say what you should get, but all of
the pre-standard compilers I know would defer name-lookup to
instantiation.) Since C++89, you should get template max; name lookup
occurs in two phases: when the template is defined (at which point, only
the template max is visible), and when the template is instantiated,
but at the instantiation point, only for dependent names, and only using
ADL. In your code, max is a dependent name, but the symbols
triggering ADL are std::vector (which draws in std) and int, which
doesn't add anything, not even the global namespace. So the
non-template max is not found.
These rules were among the last formalized by the C++ committee, and
compilers can't change overnight, so practically speaking, if the
compiler dates from anytime before 1995, you can probably expect the
pre-standard behavior. For anything later, I'd tend to consider it a
compiler error, but... compilers have to support existing code, and
ideally, later compilers will have an option to use the previous name
lookup rules. (I say ideally, because having two incompatible sets of
name lookup rules is decidedly non-trivial. Just getting one set
correct is difficult enough for most compiler implementors.)
And it's fairly well known that Microsoft's implementation of templates
is not standard conformant, even today.
The call of max in Imax depend on T and thus max should be searched in the template definition context (where the template max is) and combined with the argument dependent lookup in the instantiation context. ADL shouldn't find the free standing max as int have no associated namespace. So my take is that gcc is correct.
Note that if you have the slight variation:
#include <iostream>
#include <vector>
struct S {};
template < typename T >
inline void max( const S& a, const T& b )
{
std::cout << "template max() is called" << std::endl;
}
template < typename T >
inline void Imax( const S& a, const std::vector<T>& b)
{
max(a, b[0]);
}
inline void max( const S& a, const S& b )
{
std::cout << "non-template max() is called" << std::endl;
}
int main()
{
std::vector<S> v;
v.push_back(S());
Imax(S(), v);
return 0;
}
here, the global namespace is associated with S, and thus the non template max is found by the ADL lookup at the point of instantiation.

Function passed as template argument

I'm looking for the rules involving passing C++ templates functions as arguments.
This is supported by C++ as shown by an example here:
void add1(int &v) { v += 1 }
void add2(int &v) { v += 2 }
template <void (*T)(int &)>
void doOperation()
{
int temp = 0;
T(temp);
std::cout << "Result is " << temp << std::endl;
}
int main()
{
doOperation<add1>();
doOperation<add2>();
}
Learning about this technique is difficult, however. Googling for "function as a template argument" doesn't lead to much. And the classic C++ Templates The Complete Guide surprisingly also doesn't discuss it (at least not from my search).
The questions I have are whether this is valid C++ (or just some widely supported extension).
Also, is there a way to allow a functor with the same signature to be used interchangeably with explicit functions during this kind of template invocation?
The following does not work in the above program, at least in Visual C++, because the syntax is obviously wrong. It'd be nice to be able to switch out a function for a functor and vice versa, similar to the way you can pass a function pointer or functor to the std::sort algorithm if you want to define a custom comparison operation.
struct add3 {
void operator() (int &v) {v += 3;}
};
...
doOperation<add3>();
Pointers to a web link or two, or a page in the C++ Templates book would be appreciated!
Yes, it is valid.
As for making it work with functors as well, the usual solution is something like this instead:
template <typename F>
void doOperation(F f)
{
int temp = 0;
f(temp);
std::cout << "Result is " << temp << std::endl;
}
which can now be called as either:
doOperation(add2);
doOperation(add3());
See it live
The problem with this is that if it makes it tricky for the compiler to inline the call to add2, since all the compiler knows is that a function pointer type void (*)(int &) is being passed to doOperation. (But add3, being a functor, can be inlined easily. Here, the compiler knows that an object of type add3 is passed to the function, which means that the function to call is add3::operator(), and not just some unknown function pointer.)
Template parameters can be either parameterized by type (typename T) or by value (int X).
The "traditional" C++ way of templating a piece of code is to use a functor - that is, the code is in an object, and the object thus gives the code unique type.
When working with traditional functions, this technique doesn't work well, because a change in type doesn't indicate a specific function - rather it specifies only the signature of many possible functions. So:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op(4,5,add);
Isn't equivalent to the functor case. In this example, do_op is instantiated for all function pointers whose signature is int X (int, int). The compiler would have to be pretty aggressive to fully inline this case. (I wouldn't rule it out though, as compiler optimization has gotten pretty advanced.)
One way to tell that this code doesn't quite do what we want is:
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
is still legal, and clearly this is not getting inlined. To get full inlining, we need to template by value, so the function is fully available in the template.
typedef int(*binary_int_op)(int, int); // signature for all valid template params
template<binary_int_op op>
int do_op(int a, int b)
{
return op(a,b);
}
int add(int a, int b) { return a + b; }
...
int c = do_op<add>(4,5);
In this case, each instantiated version of do_op is instantiated with a specific function already available. Thus we expect the code for do_op to look a lot like "return a + b". (Lisp programmers, stop your smirking!)
We can also confirm that this is closer to what we want because this:
int (* func_ptr)(int,int) = add;
int c = do_op<func_ptr>(4,5);
will fail to compile. GCC says: "error: 'func_ptr' cannot appear in a constant-expression. In other words, I can't fully expand do_op because you haven't given me enough info at compiler time to know what our op is.
So if the second example is really fully inlining our op, and the first is not, what good is the template? What is it doing? The answer is: type coercion. This riff on the first example will work:
template<typename OP>
int do_op(int a, int b, OP op) { return op(a,b); }
float fadd(float a, float b) { return a+b; }
...
int c = do_op(4,5,fadd);
That example will work! (I am not suggesting it is good C++ but...) What has happened is do_op has been templated around the signatures of the various functions, and each separate instantiation will write different type coercion code. So the instantiated code for do_op with fadd looks something like:
convert a and b from int to float.
call the function ptr op with float a and float b.
convert the result back to int and return it.
By comparison, our by-value case requires an exact match on the function arguments.
Function pointers can be passed as template parameters, and this is part of standard C++
. However in the template they are declared and used as functions rather than pointer-to-function. At template instantiation one passes the address of the function rather than just the name.
For example:
int i;
void add1(int& i) { i += 1; }
template<void op(int&)>
void do_op_fn_ptr_tpl(int& i) { op(i); }
i = 0;
do_op_fn_ptr_tpl<&add1>(i);
If you want to pass a functor type as a template argument:
struct add2_t {
void operator()(int& i) { i += 2; }
};
template<typename op>
void do_op_fntr_tpl(int& i) {
op o;
o(i);
}
i = 0;
do_op_fntr_tpl<add2_t>(i);
Several answers pass a functor instance as an argument:
template<typename op>
void do_op_fntr_arg(int& i, op o) { o(i); }
i = 0;
add2_t add2;
// This has the advantage of looking identical whether
// you pass a functor or a free function:
do_op_fntr_arg(i, add1);
do_op_fntr_arg(i, add2);
The closest you can get to this uniform appearance with a template argument is to define do_op twice- once with a non-type parameter and once with a type parameter.
// non-type (function pointer) template parameter
template<void op(int&)>
void do_op(int& i) { op(i); }
// type (functor class) template parameter
template<typename op>
void do_op(int& i) {
op o;
o(i);
}
i = 0;
do_op<&add1>(i); // still need address-of operator in the function pointer case.
do_op<add2_t>(i);
Honestly, I really expected this not to compile, but it worked for me with gcc-4.8 and Visual Studio 2013.
In your template
template <void (*T)(int &)>
void doOperation()
The parameter T is a non-type template parameter. This means that the behaviour of the template function changes with the value of the parameter (which must be fixed at compile time, which function pointer constants are).
If you want somthing that works with both function objects and function parameters you need a typed template. When you do this, though, you also need to provide an object instance (either function object instance or a function pointer) to the function at run time.
template <class T>
void doOperation(T t)
{
int temp=0;
t(temp);
std::cout << "Result is " << temp << std::endl;
}
There are some minor performance considerations. This new version may be less efficient with function pointer arguments as the particular function pointer is only derefenced and called at run time whereas your function pointer template can be optimized (possibly the function call inlined) based on the particular function pointer used. Function objects can often be very efficiently expanded with the typed template, though as the particular operator() is completely determined by the type of the function object.
The reason your functor example does not work is that you need an instance to invoke the operator().
Came here with the additional requirement, that also parameter/return types should vary.
Following Ben Supnik this would be for some type T
typedef T(*binary_T_op)(T, T);
instead of
typedef int(*binary_int_op)(int, int);
The solution here is to put the function type definition and the function template into a surrounding struct template.
template <typename T> struct BinOp
{
typedef T(*binary_T_op )(T, T); // signature for all valid template params
template<binary_T_op op>
T do_op(T a, T b)
{
return op(a,b);
}
};
double mulDouble(double a, double b)
{
return a * b;
}
BinOp<double> doubleBinOp;
double res = doubleBinOp.do_op<&mulDouble>(4, 5);
Alternatively BinOp could be a class with static method template do_op(...), then called as
double res = BinOp<double>::do_op<&mulDouble>(4, 5);
EDIT
Inspired by comment from 0x2207, here is a functor taking any function with two parameters and convertible values.
struct BinOp
{
template <typename R, typename S, typename T, typename U, typename V> R operator()(R (*binaryOp )(S, T), U u, V v)
{
return binaryOp(u,v);
}
};
double subD(double a, int b)
{
return a-b;
}
int subI(double a, int b)
{
return (int)(a-b);
}
int main()
{
double resD = BinOp()(&subD, 4.03, 3);
int resI = BinOp()(&subI, 4.03, 3);
std::cout << resD << std::endl;
std::cout << resI << std::endl;
return 0;
}
correctly evaluates to double 1.03 and int 1
Edit: Passing the operator as a reference doesnt work. For simplicity, understand it as a function pointer. You just send the pointer, not a reference.
I think you are trying to write something like this.
struct Square
{
double operator()(double number) { return number * number; }
};
template <class Function>
double integrate(Function f, double a, double b, unsigned int intervals)
{
double delta = (b - a) / intervals, sum = 0.0;
while(a < b)
{
sum += f(a) * delta;
a += delta;
}
return sum;
}
.
.
std::cout << "interval : " << i << tab << tab << "intgeration = "
<< integrate(Square(), 0.0, 1.0, 10) << std::endl;