[英]Avoid ambiguity in C++
我正在尝试在我的 C 项目旁边实现一个 C++ 包装器。
因此,例如,我有"window.h"
,它具有标准的 C 包括防护。 它需要<stdlib.h>
和<string.h>
以及一些第三方库包括。
然后,我有依赖于 "window.h "window.hpp"
的"window.h"
,但使用 C++ #pragma once
并且需要<cstdlib>
和<string>
用于 C++ 实现。
我遇到了一个模棱两可的问题,其中 C/C++ 标准实现存在冲突,我不太确定该怎么做。 你可以看到我试图通过简单地检查是否定义了__cplusplus
来解决这个问题,如果是这样的话,只添加 C++ 头文件。
这个想法是你可以using namespace LittleEngine::utils;
它将为您包括 SDL 和 GLEW,并添加一些用于创建 window 的包装器功能,例如; 它使用 C++ 特性(如类)而不是 C 实现的方法。
为了理智,这就是为什么这些是单独的文件,而不仅仅是一个 header 文件,它增加了对 C 和 C++ 与extern "C" {... }
的兼容性。
“窗口.h”
#if __cplusplus
#pragma once
#endif
#ifndef LITTLE_ENGINE_UTILS_WINDOW_H_
#define LITTLE_ENGINE_UTILS_WINDOW_H_
#include <SDL2/SDL.h>
#include <GL/glew.h>
#if __cplusplus
# include <cstdio>
# include <string>
#else
# include <stdio.h>
# include <string.h>
#endif
typedef struct {
SDL_Window* window;
SDL_GLContext context;
SDL_Event event;
} Engine_GLWindow_t;
enum Engine_Window_Renderer {
VULKAN,
OPENGL
};
int Engine_CreateGLWindow(const char* title, Engine_GLWindow_t* window)
{
// Initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
fprintf(stderr, "Failed to initialize SDL.\n");
fprintf(stderr, "%s\n", SDL_GetError());
return -1;
}
// Configure window flags
Uint32 flags = 0;
flags |= SDL_WINDOW_OPENGL;
SDL_Window* sdlwin = SDL_CreateWindow(
title,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800,
600,
flags
);
if(!sdlwin)
return -1;
window->window = sdlwin;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
SDL_GL_SetSwapInterval(1);
SDL_GLContext context;
if((context = SDL_GL_CreateContext(window->window)) != NULL)
window->context = context;
else
{
SDL_DestroyWindow(window->window);
fprintf(stderr, "Failed to initialize the GL context.\n");
fprintf(stderr, "%s\n", SDL_GetError());
return -1;
}
glewExperimental = GL_TRUE;
GLenum glewCode = glewInit();
if(glewCode != GLEW_OK)
{
SDL_GL_DeleteContext(window->context);
SDL_DestroyWindow(window->window);
fprintf(stderr, "Failed to initialize GLEW.\n");
fprintf(stderr, "%s\n", glewGetErrorString(glewCode));
return -1;
}
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, 800, 600);
SDL_ShowWindow(sdlwin);
return 0;
}
int Engine_DestroyGLWindow(Engine_GLWindow_t* window)
{
SDL_GL_DeleteContext(window->context);
SDL_DestroyWindow(window->window);
SDL_Quit();
return 0;
}
#endif
“windows.hpp”
#pragma once
/*
file included as:
engine.hpp
...
namespace LittleEngine {
namespace utils {
# include "utils.hpp" // -> #include "windows.hpp"
}
}
*/
#include "window.h"
#include <cstdint>
class GLWindow {
public:
GLWindow(std::string title)
{
Engine_CreateGLWindow(title.c_str(), &this->window_data);
}
GLWindow(std::string title, bool& success)
{
if(Engine_CreateGLWindow(title.c_str(), &this->window_data) == 0)
success = true;
}
~GLWindow()
{
Engine_DestroyGLWindow(&this->window_data);
}
Engine_GLWindow_t* getWindowData()
{
return &this->window_data;
}
protected:
Engine_GLWindow_t window_data;
};
主文件
#include <LittleEngine/engine.hpp>
int main(int argc, char* argv[], char* envp[])
{
// COMMENTED CODE WORKS BTW
// Engine_GLWindow_t window;
// Engine_CreateGLWindow("LittleBird", &window);
LittleEngine::utils::GLWindow window("LittleBird");
bool should_run = true;
const LittleEngine::utils::Uint8* keys = nullptr;
while (should_run)
{
while (LittleEngine::utils::SDL_PollEvent(&window.getWindowData()->event))
if (window.getWindowData()->event.type == LittleEngine::utils::SDL_QUIT)
should_run = false;
// ensure that SDL2 updated the keyboard state
LittleEngine::utils::SDL_PumpEvents();
// // automatically update window size
// UpdateWindowSize(&window);
// SDL2 should automatically clear this memory after each loop
keys = LittleEngine::utils::SDL_GetKeyboardState(0);
// black background color
LittleEngine::utils::glClearColor(0.00f, 0.00f, 0.00f, 1.00f);
// red background color if pressing W
if(keys[LittleEngine::utils::SDL_SCANCODE_W])
LittleEngine::utils::glClearColor(1.00f, 0.00f, 0.00f, 1.00f);
LittleEngine::utils::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LittleEngine::utils::SDL_GL_SwapWindow(window.getWindowData()->window);
}
return 0;
}
因此,经过更多测试后,我的问题的答案是,您必须先将 C header 文件包装在extern "C"
中,然后再尝试将它们包含到命名空间中。
namespace LittleEngine {
namespace utils {
extern "C" {
# include "window.h"
}
# include "window.hpp"
}
}
但是,即使这样做,它仍然将 C-defines 放在根名称空间中,我想这是有道理的。
编辑:此外,它确实比这更奇怪。 在上面的例子中,我可以通过 extern-C 包含“window.h”文件。 第二个我跳到另一个文件并尝试链接 impl。 这个,我得到了与我开始时相同的错误。 TLDR; 仅 TIL C++ 在命名空间中包含 go。
编辑 2:我认为这只是 GLEW 和 SDL 造成的问题。 我讨厌编程。 我为什么要这样对自己?
编辑3:经过更多测试..我认为是。 所以我在重构时所做的最大改变是
extern "C"
,因为理论上应该做的就是禁用 C++ 名称争论,这无论如何都没有意义。不管怎样,我的观点仍然成立。 不要在 C++ 命名空间中包含 C 标头。
如果其他人想以更详细的方式回答这个问题,我很乐意将其标记为答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.