473,670 Members | 2,448 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 2893
> 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
2954
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
1645
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
1640
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
1952
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 | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)) #define MS_NBF "MNBF" #define PSN_FIRST (0U-200U)
3
1928
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
1717
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
2516
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
12582
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 { M<xRet,yReta; return a;
3
3572
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
8384
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 synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8813
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 captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8591
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8659
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 choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6212
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5683
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4388
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2037
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1791
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.