如何使我的 cmake 项目所需的某些 c++ 功能

How can I make certain c++ features required in my cmake project?

本文关键字:c++ 功能 何使 我的 cmake 项目      更新时间:2023-10-16

我正在为我的 c++14 项目编写CMakeLists.txt。我希望其他用户能够构建我的项目,但他们的编译器可能不支持我正在使用的 c++14 功能。如果编译器不支持我的 c++14 代码,如何让 cmake 打印错误消息?

我找到了target_compile_features命令,它似乎做正确的工作。但是,我不确定如何正确使用它...

这是对的吗?

CMakeLists.txt:

project(myproject VERSION 1.0.0
LANGUAGES CXX)
add_executable(myproject src/main.cpp)
target_compile_features(myproject PRIVATE cxx_auto_type)
...

因为我认为这是一个常见的问题,所以我会自己回答:

虽然一般用法是正确的,但如果你正在编写一个库,你需要调整 cmake 代码:

target_compile_features(myproject INTERFACE cxx_auto_type)

此外,您需要根据所使用的内容添加更多功能。这可以通过简单地列出它们来完成:

target_compile_features(myproject INTERFACE cxx_auto_type
cxx_static_assert
...)

CMAKE_CXX_KNOWN_FEATURES

可以在 cmake 文档中找到可能的值列表。但是,我发现简短的句子和指向 c++ 标准的链接并没有真正的帮助。因此,我将尝试描述每个选项包含哪些功能。

我想解释列表中的所有选项,但这需要很长时间来写......因此,我将从我认为有用或有趣的功能开始,但稍后会尝试添加更多功能。如果有人想添加我还没有来发布的内容,我也会不胜感激。

我将链接与原始文档相同的 c++ 标准文档,但我还将提供指向相应 cppreference 页面的链接,并在必要时提供一个小型编码示例。

cxx_auto_type

自动类型推断是在 C++11 和 N1984 中引入的。它允许用户在所有情况下编写auto关键字,编译器可以自动推断结果类型。不必再给出实际类型。

例如:

auto i = 0; //it is clear that we want an int here
auto d = 1.45; //it is clear that we want a double here
...

cxx_binary_literals

二进制文字是在 C++14 中与 N3472 一起引入的。除了现有的十六进制文字之外,它们还允许以二进制形式写入值。

二进制文本在二进制值前面用0b0B标记:

0B1000 == 8 //true
0b1001 == 9 //true

cxx_deleted_functions

删除的函数是在 C++11 中引入的 N2346。它们允许用户显式删除类中的某些运算符和成员函数。如果程序将访问任何已删除的函数,则代码将不会编译:

struct no_default_constructor {
no_default_constructor() = delete; //the default constructor is deleted
no_default_constructor(int value) : ...
...
};

因此,默认构造是不可能的,但另一个构造可能是。

no_default_constructor object = no_default_constructor(); //this will not compile
no_default_constructor object = no_default_constructor(2); //this will

cxx_explicit_conversions

在C++11 中使用 N2437 添加了显式转换。它们允许将类转换指定为显式,这意味着不可能进行隐式转换。

例如:

struct flag {
bool is_set;
explicit operator bool() const { return is_set; }
};

此类不能隐式转换为 bool,但仍可以显式转换:

void print_birthday_message(flag user_has_birthday) {
bool has_birthday = user_has_birthday; //this is not possible
bool has_birthday = bool(user_has_birthday); //but this is fine
...
}

cxx_final

最后一个关键字是在 c++11 中引入的 N2928、N3206 和 N3272。它允许类设计器防止用户覆盖虚拟函数或成员函数。

final关键字必须写在虚函数的末尾,以防止额外的覆盖:

struct Base { 
virtual void function();
};
struct A : Base {
void function() final; //overwrite Base::function and make it the final overwrite
};
struct B : A {
void function() override; //this is not possible, as function was already marked final inside A
};

final关键字必须位于派生类名的末尾,以防止覆盖:

struct Base {};
struct A final : Base {}; //struct A is now final
struct B : A {}; //this is not possible, as A was already marked final

cxx_noexcept

noexcept 关键字是在 C++11 中引入的 N3050。它允许标记函数,运算符和构造函数。如果这些被标记为noexcept,它们保证在调用它们时不会抛出任何异常。此外,"无例外性"可以通过noexcept(f)函数进行测试。

cxx_raw_string_literals

原始字符串文字是在 C++11 中引入的 N2442。它们允许在不使用转义字符的情况下将任意字符写入字符串。

原始字符串采用R"delimiter(raw_characters)delimiter"的形式,delimiter是任意名称(遵循 c++ 命名标准)。一种常见的情况是使用它们直接在 c++ 中输入脚本代码。此外,编译器会忽略delimiter,使用它来提示 IDE 脚本语言。

例如:

const char* code = R"chaiscript(
print("Hello World")
)chaiscript";

cxx_strong_enums

强类型枚举是在 C++11 中引入的 N2347。它们允许以某种方式设置枚举的类型,从而防止带有枚举的错误自动转换为其他类型的错误。

强类型枚举使用enum class name语法。例如:

enum class colours {
cyan = 0,
red = 1,
green = 2,
};

这使得意外转换变得不可能:

int color_index = colours::green; //this conversion is not allowed!
int color_index = int(colours::green); //explicit casts are still okay

cxx_trailing_return_types

尾随返回类型是在 C++11 中引入的 N2541。它们允许在参数列表之后定义函数的返回类型:

auto greet() -> void {
std::cout << "Hello World!";
}

尾随返回类型在AAA(几乎总是自动)编程风格中很有用,在返回类型很复杂的情况下,或者在模板函数中可能取决于输入类型。

cxx_unicode_literals

Unicode 文字是在 C++11 中与 N2442 一起引入的。它们允许用户直接将 unicode 字符输入到 c++ 中,而无需使用 unicode 转义字符。(n, ...还是要逃脱的。

它们采用的形式u8"(characters)".可以替换u8以更改基础数据类型:

const char* utf8 = u8"(characters)";
const char16_t* utf16 = u"(characters)";
const char32_t* utf32 = U"(characters)";

cxx_user_literals

用户文字是在 C++11 中与 N2765 一起引入的。它们允许用户编写自定义类型快捷方式和自定义类型转换。

用户文本是用operator ""定义的。例如,从度到弧度的转换可以这样写:

constexpr double operator "" _degrees(double value) {
return value*3.14/180.;
}

该值由以下方法获得:

double theta = 90_degrees; //==1.57