无法命名的C ++类型

时间:2011-03-05 22:53:03

标签: c++ templates types c++11 decltype

在阅读Wikipedia's page on decltype时,我很好奇这句话,

  

其[decltype]的主要用途是通用的   编程,经常在哪里   名字很难,甚至不可能   依赖于模板的类型   参数。

虽然我可以理解该语句的难度部分,但是需要命名一个无法在C ++ 03下命名的类型的示例是什么?

编辑:我的观点是,因为C ++中的所有内容都有类型声明。为什么会出现无法命名类型的情况?此外,是不是设计用于产生类型信息的特质类?特质课可以替代decltype吗?

3 个答案:

答案 0 :(得分:13)

您链接的维基百科页面有一个完美的例子:

int& foo(int& i);
float foo(float& f);

template <class T> auto transparent_forwarder(T& t) −> decltype(foo(t)) {
  return foo(t);
}

请注意foo(int&)返回int&(引用类型),而foo(float&)返回float(非引用类型)。如果没有decltype,则模板中不可能指定一个类型,该类型表示“函数foo的返回类型,它接受类型t的参数T”。

在这个例子中,它不是一个无法表达的特定具体类型 - int&float可以单独表达 - 而是更高级别的泛型类类型。

编辑:并回答你对另一个答案的评论,这个例子在C ++ 03中难以形容。你不能有一个函数模板,它将包装任何函数T1 foo(T2)并匹配包装函数的参数和返回类型。

答案 1 :(得分:11)

C ++ 0x中有类型(在C ++ 03中,但不常见),无法明确命名,例如声明decltype(f)后的类型auto f = [](int x) -> int {return x;};。你需要typedef decltype得到一些东西才能获得一个名字。 Traits类可用于确定返回类型,但它们很混乱,并且用户需要使用traits类重载来复制它们的所有函数重载;对于诸如函数(通过指针的隐式转换)应用于给定基类的所有子类的情况,这很难正确执行。

答案 2 :(得分:1)

正如您所指出的,编译器知道存在的类型,否则它将不存在。但是,在C ++ 03中程序员并不总是容易甚至无法访问它。

N1607在结论中提到以下内容:

  

在C ++ 2003中,不可能   表达函数的返回类型   模板在所有情况下。此外,   涉及调用的表达式   功能模板通常很有用   复杂的类型,是   实际上不可能写   手

问题是我们如何以程序员的身份访问此类型。这并不总是一个微不足道的过程,往往是不切实际的。当你有一个你想知道结果类型的表达式时,它会变得越来越复杂。为了计算结果类型,你必须将它分成几部分。使用模板无法简化此过程(无论如何都不能评估表达式)。打破表达将是容易出错,乏味和维持的噩梦。想想这段代码:

x.g()[b.a(e)]->f();

使用C ++ 98 / TR1,名称类型依赖于模板参数通常是不可行的。 Traits为我们提供了如此多的信息,但最终decltype是解决许多问题的更清晰的解决方案。元编程时可用的很多信息都是可用的,因为诸如boost或loki等库在C ++ 98语言的暗角中隐藏了一些技巧。

当然这与你的问题无关,但我相信值得一提的是C ++ 98编译器已经有机制来了解这些类型。这正是sizeof提供的,除了它返回一个大小。 decltype重用了这些功能,并以更优雅的方式解决了这些问题。

至于另一个(学术)的例子:

struct Foo
{
    struct
    {
        int x;
    } bar;
};

template<typename T>
void
f(const T& t)
{
    // C++03, How can I name the type of T::bar ?

    // C++0x
    // decltype(t.bar) cpy;
    // Do stuff with our local cpy
}

int
main()
{
    f(Foo());
}