【问题标题】:Templated typedef workaround doesn't seem to work模板化的 typedef 解决方法似乎不起作用
【发布时间】:2013-11-14 14:29:35
【问题描述】:

我正在使用 C++03(确实是 CUDA nvcc,但这没关系)。我有以下工作代码:

template<typename T> void baz(T*);

template<typename T>
void bar() {
    typedef void (*foo_t)(T*);
    static const foo_t dummy = baz;
    // use dummy
};

现在,我想将虚拟变量移出函数,使其成为全局变量。

第一次尝试:

template<typename T> void baz(T*);
template<typename T> typedef void (*foo_t)(T*);
template<typename T> const foo_t dummy = baz;

template<typename T>
void bar() {
    // use dummy
};

这不起作用,因为 C++(至少是 C++03)没有模板化 typedef:

error: "typedef" may not be specified here

error: "foo_t" is not a function or static data member

为什么 C++03 没有这个?难倒我了。如果我可以在一个函数中做到这一点,我不明白为什么我也不能在外面做到这一点。我认为 C++11 也没有(但有模板化的using,对吧?)

好的,所以我阅读了Template typedefs - What's your work around?,并选择了接受的答案 - 使用帮助类。

第二次尝试:

template<typename T> void baz(T*);
template<typename T> class TemplatingHeler {
  typedef void (*foo_t)(T*);
  static const foo_t dummy = baz;
}

...这得到:

error: a member of type "void (*const)(T *)" cannot have an in-class initializer

第三次尝试:

template<typename T> void baz(T*);
template<typename T> class TemplatingHelper {
  typedef void (*foo_t)(T*);
  static foo_t dummy;
};
template<typename T> TemplatingHelper::dummy = baz;

error: name followed by "::" must be a class or namespace name

error: argument list for class template "TemplatingHelper" is missing

...和 ​​nvcc 段错误 (!)

为什么会发生这一切,我怎样才能让它发挥作用?

【问题讨论】:

  • 您正在使用没有模板参数的模板。无论如何,第一个是变量模板,它指日可待。
  • 模板化类型定义有一个替代方案:模板化using。你应该使用using(不要与“你需要移动它移动它”混淆)。
  • @stefan:模板化using 不是 C++11 的一个特性吗?无论如何,你能在某处举个例子或链接吗?
  • C++0x 是 C++11 的旧名称。较旧的标准称为 C++03。
  • 哦,也许我可以帮忙!您遇到了什么具体错误?

标签: c++ templates typedef c++03


【解决方案1】:

修复错误后,您的第三次尝试应该可以工作;)

template<typename T> void baz(T*);
template<typename T> class TemplatingHelper {
  typedef void (*foo_t)(T*);
  static foo_t dummy;
};

template<typename T>                   // template-declaration
typename TemplatingHelper<T>::foo_t    // type
TemplatingHelper<T>::dummy             // name
= baz;                                 // initializer

我同意这是多余的,但它遵循一般的声明形式:

type name initializer ;

即使名称已经在类模板中声明并指定了类型。

在这种情况下,它是一个模板声明,所以我们需要添加template&lt;typename T&gt; 部分;这是必需的,因为我们也可以参考部分特化:

template<typename T, typename U> class TemplatingHelper<T(*)(U)>
{
    typedef T(*foo_t)(U);
    static foo_t dummy;
};

template<typename T, typename U>
typename TemplatingHelper<T(*)(U)>::foo_t
TemplatingHelper<T(*)(U)>::dummy
= baz;

由于类型是必需的并且在声明的名称之前,我们需要明确说明在哪里找到它的范围:

TemplatingHelper<T>::foo_t

不幸的是,名称查找需要在此限定名称之前放置一个typename。见Where and why do I have to put the “template” and “typename” keywords?

【讨论】:

  • 这一定是我见过的最做作的 C++ 代码......为什么我需要 @#$k 来指定已经声明的东西的类型?为什么我需要在类型名之前加上typename 关键字?
  • @einpoklum 我试图解释它..部分..在更新的答案中;在 C++11 中有更简单的方法(除了别名模板 = 模板 typedef),例如template&lt;typename T&gt; decltype(TemplatingHelper&lt;T&gt;::dummy) TemplatingHelper&lt;T&gt;::dummy = baz;(使用宏更简单),但我遇到了使用这个.. 的编译器错误。此外,constexpr 允许在类定义中初始化 dummy
  • 我不明白为什么初始化语句需要是声明的格式。 dummy 已被声明。假设TemplatingHelper 不是模板类,dummy 只是一个 int。我不能用TemplatingHelper::dummy = 7这个语句来初始化它吗?
  • @einpoklum "难道我不能用语句来初始化它吗" 不行。原因是它不仅仅是一个初始化,而是一个定义我>。 IE。该语句还定义了在链接之前将变量放置在哪个目标文件中。 (从任何其他翻译单元,它被称为extern 变量。)作为一个定义,它本身也是一个声明(重新声明)。当然,这只是它的定义。解析可能更简单,因为它不是特殊情况,而只是另一种定义。正如我所说,编译器可以推断数据类型(-> decltype)。
猜你喜欢
  • 1970-01-01
  • 2023-01-02
  • 2012-08-25
  • 1970-01-01
  • 2023-02-04
  • 1970-01-01
  • 2021-11-27
  • 2021-09-13
  • 1970-01-01
相关资源
最近更新 更多