请考虑以下示例:
#include <iostream>
template<typename T>
void f(T t) {
std::cout << t << '\n';
static_assert(std::is_same<T, int const*>::value, "T != int const*");
static_assert(std::is_same<decltype(t), int const*>::value, "decltype(t) != int const*");
}
template<typename T>
void g(T t) {
std::cout << t << '\n';
static_assert(std::is_same<T, int>::value, "T != int");
static_assert(std::is_same<decltype(t), int>::value, "decltype(t) != int");
t++;
}
int main()
{
int x = 22;
int const* px = &x;
f(px);
int const& rx = x;
g(rx);
}代码正常执行。但根据现行规则我们得到:
T == int const*和t在调用f(px)中模板函数f的实例化中具有int const*类型。T == int和t在调用g(rx)中模板函数g的实例化中具有int类型。我对第二个推论的第一个想法将是与指针情况对称的东西,即使用T == int const&和带有int const&类型的t。
我想我知道编译器执行的当前演绎过程是怎么回事。根据第5.5节,引用将被删除在传递给rx的表达式g中。也就是说,用于参数推导的rx类型是int const。请注意,随着这一更改,const (在rx声明中是而不是顶层)变成了顶级const。然后,在第三个项目点(§14.8.2.1/2 )中,const在int const类型中被忽略,因为它现在是顶级const。
在我看来,这个计划似乎是相当人为的。因此,我在想,为什么第5/5节必须应用于一个用于推断模板参数的表达式?必须有一个更有力的理由来证明这条规则是合理的,我不知道。这就是我想知道的。谢谢。
发布于 2014-07-18 17:08:29
关于基本原理,让我们首先考虑为什么const不进行参数类型推断:
template< class Type >
void foo( Type v ) { v = 0; }
auto main() -> int
{
int const x = 3;
foo( x );
}这很好地编译,因为C++11§14.8.2.1/2第三个破折号是这么说的,“对于类型的演绎,忽略了A类型的顶级cv-限定符”。
我猜这其中很大一部分的理由是,否则各种实际的参数cv限定都会产生完全相同的函数类型的函数模板实例化,因为形式参数的顶级cv限定被忽略了wrt。函数的类型。这样的实例化可以产生截然不同的效果。会很乱的。
那么,关于为什么删除引用,嗯,它们不是这个程序,
#if defined( USE_REF )
# define Q &&
auto kind = "ref";
#else
# define Q
auto kind = "non-ref";
#endif
template< class A1, class A2 >
void foo( A1 a1, A2 a2 )
{
a1 ^= a2;
a2 ^= a1;
a1 ^= a2;
}
#include <iostream>
#include <typeinfo>
auto main() -> int
{
using namespace std;
int Q a1 = 111;
int Q a2 = 222;
foo( a1, a2 );
cout << kind << ' ' << a1 << ' ' << a2 << endl;
}会根据USE_REF的不同顺序输出数字吗?
但事实并非如此。
这是因为引用的设计使得a1 (在C++03中是对int的引用)与a1 (直接是int )是无法区分的。
对于更明确和更知情的基本观点(上面的观点非常可信,但仍然只是我对它的想法),的“C++的设计和进化”一书可能包含了一些东西。或者不是。不幸的是我没有那本书。
https://stackoverflow.com/questions/24828832
复制相似问题