且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

整数文字的模板参数推导

更新时间:2023-11-30 22:33:34

&gt嗨大家好,

我真的很想帮助解释这个明显的差异,
因为我真的没有得到它。这是片段:

void foo(int&);
void foo(int const&);

template< typename T>
void bar(T&);

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




您的编译器会给出相应的消息c annot将参数1从

''int''转换为''int&''"。一个basic_type常量(而不是basic_type变量)

不能绑定到左值,那么它就不能将10转换为int&因此选择foo(int const&)并且那个栏不起作用。

-

JS


您好Jean-Sebastien,
您的编译器提供了相应的消息无法从''int'转换参数
1 '到''int&''"。 basic_type常量(而不是basic_type
变量)不能绑定到左值,然后它不能将10转换为int&因此
选择foo(int const&)并且该栏不起作用。




是的,我理解为什么编译器会给出消息。根据推导出模板参数的方式,消息是




我不明白为什么语言的模板参数

推算是如此愚蠢,以至于它为传递的

rvalue选择一个非常量类型,而编译器完全清楚那是'*从不*

将产生一个有效的调用,因为该类型是通过引用传递的。

AFAIK扣除模板参数是

之间的统一过程类型传递的值和函数中列出的类型

原型。但是int&并不与整数右值统一*完全*!


当10时被传递给具有参数T&的模板函数。然后

恕我直言,它应该使T =" int const"而不是int,如果标准

目前另有说明,那么我真诚地希望这将改变

。 :)


其他人对此有何看法?


- 巴特


&GT;当10时被传递给具有参数T&的模板函数。然后
恕我直言,它应该使T =" int const"而不是int,如果标准
目前另有说明,那么我真诚地希望这将会改变。 :)




不能因为10的类型为int而不是const int。如果你有

类似


模板< class T>

void bar_impl(T&){/ *做某事* /}


模板< class T>

void bar(T& t){bar_impl(t); }


模板< class T>

void bar(const T&){bar_impl(t); }


然后bar(10)可以工作(并且将调用bar_impl< const int>)。

-

JS


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<typename 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<typename 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,const
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<typename T, typename T1>
void my_new(T1& a1)
{
}
template<typename 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

> 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<typename 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


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


> 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