【问题标题】:How can I make certain c++ features required in my cmake project?如何使我的 cmake 项目中需要某些 c++ 功能?
【发布时间】:2018-12-30 00:08:43
【问题描述】:

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

我找到了target_compile_featurescommand,这似乎是正确的工作。但是,我不确定如何正确使用它...

是这样吗?

CMakeLists.txt:

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

【问题讨论】:

  • 虽然答案很好,但问题似乎不是。你说“......我真的不知道什么是正确的。我应该为我的项目使用哪些?”,但你没有指定什么确切目的你需要这些标志.您的回答适合 Stack Overflow 上的文档页面,但它们已经消失了。请注意,Stack Overflow 的 Q/A(问题/答案)格式并不适合所有有用的信息。不过,您可以创建博客。
  • 嗯...我最近才开始使用Stack Overflow,所以对行为不太了解。你有什么建议?改写问题?做点别的吗?博客可能是一个想法,但我对创建一个并不真正感兴趣。还是 Stack Overflow 中有一些博客功能?
  • 不,据我所知,Stack Overflow 没有自己的博客功能。重新表述这个问题......我不确定是否可以提出这个问题,这既适合 Stack Overflow 规则,也适合给定答案。如果我是开发人员,我会问“我的代码使用 c++11 功能 。我知道并非所有编译器都支持它们。如何检查 CMake 是否支持这些功能? ”。所以答案是“使用target_compile_features 和以下参数:...”。在答案的最后,您可以描述 CMake 支持的其他功能。
  • 您也可以在Meta Stack Overflow 上询问给定问题的可能改进。通过这种方式,您可以收集更多的想法(可能还有很棒的想法)。但是,在这种情况下,请准备好“元效应” - 给定的问题将比现在吸引更多的观点,并且更多的用户可以标记它,无论是正面的还是负面的。
  • @Tsyvarev 感谢您的回答。我不确定我是否想问 Meta... 但是,我尝试了一些改写。现在怎么样?

标签: c++ c++11 cmake c++14


【解决方案1】:

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

虽然一般用法是正确的,但如果您正在编写库,则需要调整 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 documentation 中找到可能值的列表。但是,我发现 c++ 标准的简短句子和链接并没有真正的帮助。因此,我将尝试描述每个选项所包含的功能。

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

我将链接与原版相同的 c++ 标准文档,但如果需要,我还将提供指向相应 cppreference 页面的链接和一个小的编码示例。

cxx_auto_type

Auto type deduction 是在 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

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

二进制字面量在二进制值前面用0b0B 标记:

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

cxx_deleted_functions

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

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

final keyword 是在 c++11 中引入的,带有 N2928N3206N3272。它允许类设计者防止用户覆盖虚函数或成员函数。

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 keyword 是在 c++11 中与N3050 一起引入的。它允许标记函数、运算符和构造函数。如果这些标记为noexcept,则它们保证在调用它们时不会引发异常。此外,“noexceptness”可以通过noexcept(f) 函数进行测试。

cxx_raw_string_literals

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

Strongly typed 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

Trailing return types 是在 c++11 中以N2541 引入的。它们允许在参数列表之后定义函数的返回类型:

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

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

cxx_unicode_literals

Unicode literals 是在 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

User literals 是在 c++11 中以N2765 引入的。它们允许用户编写自定义类型快捷方式和自定义类型转换。

用户文字使用operator "" 定义。例如,从度数到弧度的转换可以写成:

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

该值通过以下方式获得:

double theta = 90_degrees; //==1.57

【讨论】:

    猜你喜欢
    • 2019-06-19
    • 1970-01-01
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    相关资源
    最近更新 更多