C++ - 前向声明和别名(使用using或typedef)

13

我需要实现以下接口

struct mutex;
struct interface
{
  //...
  mutex& getMutex();
};

我的直觉告诉我可以在我的实现中使用 using mutex = ParticularMutex,但gcc告诉我不行:

直觉告诉我可以使用 using mutex = ParticularMutex 在我的实现中,但是gcc告诉我不能:

error: conflicting declaration ‘using mutex = ’
error: ‘class mutex’ has a previous declaration as ‘class mutex’

我并没有两次定义任何东西,只是像前向声明时一样声明了两次,所以

  1. 为什么这不起作用?
  2. 是否有一种方法可以解决问题而不修改 interface
  3. 应该如何定义 interface?使用 template <typename mutex> 吗?
4个回答

12
  1. 它不能工作,因为前置声明 struct mutex; 告诉编译器 mutex 是一种新类型。使用 using 语句创建了一个类型别名,这意味着它不是一个新的类型(承诺给编译器的),而是现有类型的别名。

  2. 不。

  3. 是的。


可以做的是:

struct mutex : ParticularMutex {
    using ParticularMutex::ParticularMutex; // inherit constructors
};

定义一个从ParticularMutex派生的类型,希望它足够兼容。当然,这是一个新类型,可能会引起其他问题。


4
但我不明白为什么编译器要关心这个。我想知道是否有一种前向声明的方式,可以表示“这个名称代表某种类型。你现在不需要知道准确的定义,但是链接时会有它”。 - ricab
1
@ricab 编译器关心这个,因为这是标准要求的。无论它是否有用或者是否应该有某种方式来前向声明类型别名,这是一个不同的问题。而且坦率地说,模板参数正是这样:它告诉“接口”你将在以后提供一些类型(或类型别名)。 - Daniel Frey
@ricab 我更新了答案并提供了可能的解决方案,请检查它是否适用于您。 - Daniel Frey
1
是的,我在想标准为什么不包含更一般的前向声明机制。当使用typedef定义mutex时,我没有看到相关的语义变化。 - ricab
另外,你的解决方案可行。你需要将第2个答案从“否”修改为“是” :) 顺便说一下,值得注意的是,gcc4.7不支持以那种方式_使用_构造函数(我不得不使用在线编译器来确认它) - ricab
@ricab 我会放弃第二个,因为我认为这不是解决根本问题的方法,这只是你如何定义“互斥锁”。无论如何,我很高兴它对你有所帮助(虽然构造函数继承是C++11的特性,并且在旧版本编译器中没有实现)。 - Daniel Frey

1
在类似的情况下(与JNI抽象一起工作),这是我所做的:
不了解JNI的文件 MyObject.h
class PlatformObject; // forward declaration
struct MyObject {
        int accumulator;
        PlatformObject* platformObj;
};

JNI感知文件 jniBridge.cpp:

#include <jni.h>
#define PlatformObject _jobject
#include "MyObject.h"

void attach(MyObject& obj, jobject parent) {
    obj.platformObj = env->GetObjectField(parent, child_FieldID);
}

void add(MyObject& obj, int k) {
    accumulator += k;
    env->CallVoidMethod(obj.platformObj, add_MethodID, k);
}

已接受的答案对于add()有效,但对于attach()无效;后者需要额外的static_cast

我认为在某些情况下,两种方法都有优劣之处。


0
  • 首先你说mutex是一个具体的类类型。然后稍后你又说“哦,等一下,mutex并不是它自己的类型,它实际上是这个其他类型”。编译器在这种情况下不知道该怎么做。

  • using替换struct mutex,应该就可以工作了(我对C++11的使用没有完全跟上)。

  • 如果您想支持多个互斥锁实现,可能需要将接口制作为模板(或使用互斥锁抽象接口,通过虚拟方式决定调用哪个互斥锁实现)。


谢谢,关于第二点:我可能没有表达清楚,但我的意思是“是否有一种解决方法,而不需要修改包含‘interface’和前向声明的‘文件’?” - ricab

0

嗯,通常可以通过在其中一个头文件中添加 ParticularMutex 的存根声明来解决此问题。类似于:

namespace foreignlib {
    namespace foreignsublib {
        class ParticularMutex;
    }
}

然后在您的通用头文件中:

namespace ourlib {
    using mutex = foreignlib::foreignsublib::ParticularMutex;
}

这样做效果很好,解析和编译速度快。优点是:任何阅读你一般头文件的人都知道,到底你特定的mutex是什么。缺点是:你无法编写一个互斥锁不可知的库,在稍后使用using指令时可以放置其中一个或另一个互斥锁。如果您想要或需要这样做,C++之神希望您使用模板。但这也有它自己的代价...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接