应该如何在 C++ 库中包含全局定义的常量?

问题描述 投票:0回答:1

我将使用一个具体的(尽管是简化的)示例来说明我的意思。假设我们正在开发一个与复数相关的库。我们定义了两个类,“cmplx”表示复数,“meta”是使用“cmplx”定义其成员的类。我们想要提供这些类的 3 个常量实例:“cmplx0”、“cmplxi”和“meta0”。当我展示代码时,你会看到,cmplx0 = 0+0*i,cmplxi = 0+i,而meta只是我为了表达我的观点而编造的一些废话。重点是这些变量中的每一个都代表数学对象的特定实例,我们希望用户能够像使用“1”或“M_PI”一样使用它们。问题是当我尝试编译时,我不断收到链接错误。

我一直在参考这个问题,但没有取得任何成功。我在下面提供了一个示例,当我运行它时,我收到“错误:ld 返回状态 1”。我在 Windows 10 上使用 VS Code 和 g++。目录结构如下所示:

\headers
\headers\cmplx.h
\headers\meta.h
\sources
\sources\cmplx.cpp
\sources\meta.cpp
\examples
\examples\test.cpp
\lib.h
\makefile

cmplx.h

#ifndef class1_h
#define class1_h

#include <iostream>

namespace CMPLX
{
    class cmplx {
        public:
            double re;//real part
            double im;//imaginary part        
            cmplx();
            cmplx(double x, double y);
            friend std::ostream& operator<< (std::ostream& os, cmplx x){
                return os << x.re << "+i*(" << x.im << ")" << std::endl;
            }
    };

    extern const cmplx cmplx0;
    extern const cmplx cmplxi;
};
#endif

meta.h

#ifndef class2_h
#define class2_h

#include "cmplx.h"

namespace CMPLX
{
    class meta {
        private:
            double value1;
            cmplx value2;
        public:
            meta();
            meta(int x, cmplx y);
            friend std::ostream& operator<< (std::ostream& os, meta x){
                return os << x.value1 << " " << x.value2 << std::endl;
            }
            meta operate();
    };

    extern const meta meta0;
};
#endif

cmplx.cpp

#include "cmplx.h"

using namespace CMPLX;

const cmplx cmplxi = cmplx(0.0, 1.0);
const cmplx cmplx0 = cmplx(0.0, 0.0);

cmplx::cmplx(){
    this->re = 0;
    this->im = 1;
}

cmplx::cmplx(double x, double y){
    this->re = x;
    this->im = y;
}

meta.cpp

#include "cmplx.h"
#include "meta.h"

using namespace CMPLX;

const meta meta0 = meta(0.0, cmplxi);

meta::meta(){
    this->value1 = 0.0;
    this->value2 = cmplx0;
}

meta::meta(int x, cmplx y){
    this->value1 = x;
    this->value2 = y;
}

meta meta::operate(){
    double temp = this->value1;
    this->value1 = this->value2.re;
    this->value2.re = this->value2.im;
    this->value2.im = temp;
}

test.cpp

#include "lib.h"
#include <iostream>

using namespace CMPLX;

int main(){
std::cout << cmplx0 << std::endl;
std::cout << cmplxi<< std::endl;
std::cout << meta0<< std::endl;
std::cout << meta(0.5, cmplxi).operate() << std::endl;

return 0;
}

lib.h

#ifndef lib_h
#define lib_h

#include "cmplx.h"
#include "meta.h"

#endif

makefile

# Compiler and flags
CXX = g++
CXXFLAGS = -Wall -g -Iheaders

# Directories
SRC_DIR = sources
OBJ_DIR = obj
BIN_DIR = bin
XPL_DIR = examples

# Target name
TARGET = $(BIN_DIR)/lib.lib

# Find all source files in the SRC_DIR
SRCS = $(wildcard $(SRC_DIR)/*.cpp)

# Create a list of object files by replacing .cpp with .o
OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRCS))

# Find all example files in the XPL_DIR
XPLS = $(wildcard $(XPL_DIR)/*.cpp)

# Create a list of executible files by replacing .cpp with .exe
EXES = $(patsubst $(XPL_DIR)/%.cpp, $(BIN_DIR)/%.exe, $(XPLS))

# Default target
all: library examples

examples: $(EXES)

library: $(TARGET)

$(BIN_DIR)/%.exe: $(XPL_DIR)/%.cpp
    if not exist $(BIN_DIR) mkdir $(BIN_DIR)
    $(CXX) $(CXXFLAGS) -o $@ $< $(BIN_DIR)/lib.lib

# Linking
$(TARGET): $(OBJS)
    if not exist $(BIN_DIR) mkdir $(BIN_DIR)
    ar rcs $@ $^

# Compilation
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
    if not exist $(OBJ_DIR) mkdir $(OBJ_DIR)
    $(CXX) $(CXXFLAGS) -c $< -o $@ 

# Clean up
clean:
    del $(OBJ_DIR) $(BIN_DIR)

.PHONY: all clean

如果您能给我任何反馈,我将不胜感激。要么是如何使上述方法发挥作用,要么是实现相同结果的更好方法。

c++ linker g++ mingw static-libraries
1个回答
0
投票

在 C++17 或更高版本中:

namespace CMPLX
{
    ...

    inline constexpr cmplx cmplx0{0.0, 0.0};
    inline constexpr cmplx cmplxi{0.0, 1.0};
};

C++17 之前版本

namespace CMPLX
{
    ...

    cmplx& getCmplx0()
    {
        static cmplx cmplx0{0.0, 0.0};   // Note the static.
                                         // Created once (on first use) same value always returned
        return cmplx0;
    }
    cmplx& getCmplxi()
    {
        static cmplx cmplxi{0.0, 1.0};   // Note the static.
                                         // Created once (on first use) same value always returned
        return cmplxi;
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.