473,569 Members | 2,822 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Template argument deduction on integer literals

Hi everybody,

I would really like some help explaining this apparent discrepancy,
because I really don't get it. Here is the snippet:
void foo(int&);
void foo(int const&);

template<typena me T>
void bar(T&);

int main()
{
foo(10); // calls foo(const int&)
bar(10); // calls bar<int>(int&)
}

The discrepancy is that apparently in the call to bar(), "10" is
interpreted as a const int, while in the call to bar(), "10" is
interpreted as a _non-const_ int. This behaviour is seen in g++ 3.3.5,
MSVC++ 7.1 and Comeau. To make things worse, the second call is then
always _rejected_ by the compiler, because (quoting MSVC++ 7.1):
"cannot convert parameter 1 from 'int' to 'int &': A reference that is
not to 'const' cannot be bound to a non-lvalue". So why is the "const
int" overload selected when no templates are involved, but the "int"
overload with the template?

For those interested, a bit of context on how I ran into this. In
MSVC++ 6.0 we had a "pass-through" construct for function arguments,
which boiled down to something like this:

template<typena me T, typename T1, typename T2, typename T3>
void my_new(T1& a1, T2& a2, T3& a3)
{
/* ... */
new T(a1, a2, a3)
/* ... */
}

The reason we needed this was because we wanted to "wrap" the
constructed object into some other object (in our case, a container for
reference counting information) and only return a reference to that
object, but we still needed to pass constructor parameters. *Any* set
of constructor parameters, because it was a completely generic system.
So, we had a function template like this for any number of arguments
between 0 and 20, and it worked perfectly. If we would do something
like my_new<Foo>(10, 20,30), then MS VC++ 6.0 would use my_new<Foo,cons t
int,const int,const int>. But now that we're trying this in newer, more
compliant compilers, it suddenly doesn't work, and we haven't found
another simple way of building a "generic argument passthrough" that
works. The only solution we've found is to add overloads for any
combination of const and non-const parameters:

template<typena me T, typename T1>
void my_new(T1& a1)
{
}
template<typena me T, typename T1>
void my_new(const T1& a1)
{
}

int main()
{
// This calls my_new<Foo,int> (const int&) -- even though the
// template argument is deduced as non-const int, the const
// overload is then selected. Again, WHY? :)
my_new<Foo>(10) ;
}

But the number of const/non-const combinations rises exponentially with
the number of arguments, so it's already not feasible to do this for
the versions with over five arguments. :( So, we're basically out of a
good way to do generic passthrough. If anybody has any ideas on how we
could simulate a decent passthrough (that preserves reference
semantics, no copies allowed, and that selects the right overload when
passing the data on to another function!) I'd be much obliged...

Regards,
Bart Samwel

Jul 23 '05 #1
14 2877
> Hi everybody,

I would really like some help explaining this apparent discrepancy,
because I really don't get it. Here is the snippet:
void foo(int&);
void foo(int const&);

template<typena me T>
void bar(T&);

int main()
{
foo(10); // calls foo(const int&)
bar(10); // calls bar<int>(int&)
}


Your compiler gives the appropriate message "cannot convert parameter 1 from
'int' to 'int &'". A basic_type constant (and not a basic_type variable)
cannot be bound to a lvalue then it cannot convert 10 to int& hence the
selection of foo(int const &) and that bar won't work.
--
JS
Jul 23 '05 #2
Hi Jean-Sebastien,
Your compiler gives the appropriate message "cannot convert parameter 1 from 'int' to 'int &'". A basic_type constant (and not a basic_type variable) cannot be bound to a lvalue then it cannot convert 10 to int& hence the selection of foo(int const &) and that bar won't work.


Yes, I understand why the compiler gives the message. The message is
correct given the way the template parameters are deduced.

What I don't understand is why the language's template argument
deduction is so stupid that it selects a non-const type for a passed
rvalue when it's perfectly clear to the compiler that that's *never*
going to yield a valid call because the type is passed by reference.
AFAIK deduction of template arguments is a unification process between
the types of the passed values and the types listed in the function
prototype. But "int &" doesn't unify with "integer rvalue" *at all*!

When "10" is passed to a template function that has argument "T&" then
IMHO it should make T = "int const" and not "int", and if the standard
currently says otherwise then I sincerely hope that this will be
changed. :)

Anybody else have an opinion on this?

--Bart

Jul 23 '05 #3
> When "10" is passed to a template function that has argument "T&" then
IMHO it should make T = "int const" and not "int", and if the standard
currently says otherwise then I sincerely hope that this will be
changed. :)


It can't because 10 has type "int" not "const int". If however you had
something like

template <class T>
void bar_impl (T &) { /* do something */ }

template <class T>
void bar (T & t) { bar_impl(t); }

template <class T>
void bar (const T &) { bar_impl(t); }

Then bar(10) would work (and bar_impl<const int> would be called).
--
JS
Jul 23 '05 #4
Jean-Sebastien Samson wrote:
When "10" is passed to a template function that has argument "T&" then
IMHO it should make T = "int const" and not "int", and if the standard
currently says otherwise then I sincerely hope that this will be
changed. :)

It can't because 10 has type "int" not "const int". If however you had
something like

template <class T>
void bar_impl (T &) { /* do something */ }

template <class T>
void bar (T & t) { bar_impl(t); }

template <class T>
void bar (const T &) { bar_impl(t); }


I am sure you meant

template <class T>
void bar (const T &t) { bar_impl(t); }

otherwise there's no 't'...

Then bar(10) would work (and bar_impl<const int> would be called).


V
Jul 23 '05 #5
>> template <class T>
void bar (const T &) { bar_impl(t); }


I am sure you meant

template <class T>
void bar (const T &t) { bar_impl(t); }

otherwise there's no 't'...


Yes. My apologies...
--
JS
Jul 23 '05 #6
>Then bar(10) would work (and bar_impl<const int> would be called).

I'd already thought about that, but that solution makes it extremely
difficult to "preserve" or "follow" the constness of a larger number of
parameters. I.e., if I want to do this for a bar_impl with ten
parameters, then I'll need 2^10=1024 overloads of "bar", one for every
possible combination of const/non-const parameters. For twenty
parameters this becomes 1024*1024, so this solution is infeasible. I've
thought about using a "wrapper class", but template argument deduction
only works when the types can match exactly (i.e. I can't let it deduce
"T = int" for a function argument of type "wrapper<T> " by passing "10"
and letting wrapper<int> have a constructor taking an integer). That
means I'm stuck with whatever I can deduce from the types that are
being passed, and there's apparently no efficient way of preserving
both the constness AND rvalueness AND referenceness of the type that is
being passed.

And the compiler _ knows_ that 10 is an rvalue and that it therefore
cannot be bound to a non-const reference. AFAICT it would be an
extremely simple addition to the standard to change this, so that it
deduces template arguments from rvalues as if they were "const". The
next question is why rvalues are non-const anyway, you can't modify
them but they aren't const, what is that about? If anybody in the know
would please enlighten me I'd be very grateful. :)

--Bart

Jul 23 '05 #7
Bart Samwel wrote:
[...] The
next question is why rvalues are non-const anyway, you can't modify
them but they aren't const, what is that about? If anybody in the know
would please enlighten me I'd be very grateful. :)


Who said you can't modify rvalues?

#include <iostream>
struct A {
int a;
A(int a) : a(a) {}
void changeto(int a) { this->a = a; }
~A() { std::cout << "~A(): a = " << a << std::endl; }
};

A foo() {
return A(42);
}

int main() {
foo().changeto( 20); // r-value is changed
}

What you can't modify is _literals_. rvalues (like in this example)
can designate objects, which of course are modifiable.

V
Jul 23 '05 #8
> there's apparently no efficient way of preserving
both the constness AND rvalueness AND referenceness of the type that is
being passed.


I know that won't help you but why would you want that anyway ? I am
honestly curious what code you would apply to a constant litteral which
would require an argument of "T &" and not "const T &".
--
JS
Jul 23 '05 #9
Victor Bazarov wrote:
What you can't modify is _literals_. rvalues (like in this example)
can designate objects, which of course are modifiable.


Funny. If I do:

typedef int A;

A foo()
{
return A();
}

void bar(A&)
{
}

int main()
{
bar(foo());
}

Then my compiler tells me "A reference that is not to 'const' cannot be
bound to a non-lvalue", i.e. foo() is a non-lvalue. However, the
following compiles just fine:

class A
{
};

A foo()
{
return A();
}

void bar(A&)
{
}

int main()
{
bar(foo());
}

Which indicates that either my compiler's error message is wrong, or
foo() is not a non-lvalue (i.e., it is an lvalue) in this case, because
if foo() would have been an rvalue (and therefore a non-lvalue) then it
would not have been allowed to have been bound to a non-const
reference. I've checked the standard, and it says the compiler's error
message is indeed wrong (or at least incomplete)

[from basic.lval] An lvalue for an object is necessary in order to
modify the object except that an rvalue of class type can also be used
to modify its referent under certain circumstances. [Example: a member
function called for an object (class.mfct) can modify the object. ]

OK, so you're right about rvalues. So if I understand things correctly
we not only have the lvalue/rvalue distinction, but we also have
modifiable versus nonmodifiable rvalues. Sheesh! IIRC, when
nonmodifiable rvalues appear they cause havoc in other areas as well,
e.g. std::vector iterators implemented as simple pointers, where
(++somevector.b egin()).foo() fails because somevector.begi n() does not
yield a modifiable rvalue. I just hope there is a process going on
somewhere to fix all these places where nonmodifiable rvalues make
things "not work". Wouldn't you agree that there is something tobe
fixed here?

--Bart

Jul 23 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
2937
by: Suzanne Vogel | last post by:
Is it possible to store a pointer to a template function? eg, template<class T> fooFunc() {...} fptr = fooFunc; // <-- I couldn't find any info here, not even in the forums: http://www.function-pointer.org/
4
1640
by: Dave | last post by:
Hello all, Consider this template: template <typename T> void foo(T bar) {...} Here are three ways to instantiate this: 1.
2
1635
by: marco | last post by:
the problem: I use a typedef inside a class template, than I use this type (dim_v<N1>::Type) to define the argument of a template function f but when I call this function from main, the compiler (gcc 3.4.1) tell me: "no matching function found". If someone, more expert than me, could tell me what is wrong I would be very happy
8
1949
by: Thomas Heller | last post by:
I need to convert C preprocessor definitions into python code. The definitions are dumped out of gccxml (see http://www.gccxml.org) , running over the windows header files (for example). This creates output like this (some excerpts): #define DATABITS_8 ((WORD)0x0008) #define KEY_WRITE ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE |...
3
1916
by: BigMan | last post by:
Here is a piece of code: #include <memory> using namespace std; template< typename SomeType > void f(auto_ptr_ref< SomeType >) { }
1
1713
by: Peng Yu | last post by:
Hi All, In the book Working Paper for Draft Proposed International Standard for Information Systems$)A!* Programming Language C+ +, template argument deduction is discussed. However, the discussion in the above book is too abstract to read.
4
2506
by: George | last post by:
Dear All, I'm compiling the code below with IBM's xlC 6.0 and get the message, "rmspace.cpp", line 34.48: 1540-0298 (S) Template argument deduction cannot be performed using the function "template bool space_pred(basic_string<T,char_traits<T>,allocator<T> >::value_type)". If I use gcc4.0..2, I get,
7
12576
by: gretean | last post by:
I have a problem that's driving me crazy involving Microsoft's ability to deduce template parameters. I am using Visual Studio .NET (aka VC7?), and it gives an error compiling the following code. template <int x, int yclass M { public: template <int xRet, int yRet, int xR, int yR> M<xRet, yRetoperator *(const M<xR, yR&b) const {...
3
3563
by: Fei Liu | last post by:
Hello, We all know that a template function can automatically deduce its parameter type and instantiate, e.g. template <tpyename T> void func(T a); func(0.f); This will cause func<floatto be instantiated. The user does not have
0
7704
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7620
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7931
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
8139
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
7985
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
6298
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
0
3666
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3659
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1230
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.