首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类似于“constexpr”但用于类定义的

类似于“constexpr”但用于类定义的
EN

Stack Overflow用户
提问于 2016-12-13 10:30:43
回答 3查看 7.1K关注 0票数 20

if constexpr是摆脱C++程序中预处理器的一个重要步骤。但是,它只在函数中工作--如本例中所示:

代码语言:javascript
复制
enum class OS
{
    Linux,
    MacOs,
    MsWindows,
    Unknown
};

#if defined(__APPLE__)
constexpr OS os = OS::MacOs;
#elif defined(__MINGW32__)
constexpr OS os = OS::MsWindows;
#elif defined(__linux__)
constexpr OS os = OS::Linux;
#else
constexpr OS os = OS::Unknown;
#endif

void printSystem()    
{
    if constexpr (os == OS::Linux)
    {
        std::cout << "Linux";
    }
    else if constexpr (os == OS::MacOs)
    {
        std::cout << "MacOS";
    }
    else if constexpr (os == OS::MsWindows)
    {
        std::cout << "MS Windows";
    }
    else
    {
        std::cout << "Unknown-OS";
    }
}

但是,摆脱预处理器的梦想并不十分令人满意--因为下面的示例没有编译:

1不能在类定义中使用它来以不同方式定义类的某些成员:

代码语言:javascript
复制
class OsProperties
{
public:
    static void printName()
    {
        std::cout << osName;
    }
private:
    if constexpr (os == OS::Linux)
    {
        const char* const osName = "Linux";
    }
    else if constexpr (os == OS::MacOs)
    {
        const char* const osName = "MacOS";
    }
    else if constexpr (os == OS::MsWindows)
    {
        const char* const osName = "MS Windows";
    }
    else
    {
        const char* const osName = "Unknown";
    }
};

2也不适用于非类范围(如全局范围):

代码语言:javascript
复制
if constexpr (os == OS::Linux)
{
    const char* const osName = "Linux";
}
else if constexpr (os == OS::MacOs)
{
    const char* const osName = "MacOS";
}
else if constexpr (os == OS::MsWindows)
{
    const char* const osName = "MS Windows";
}
else
{
    const char* const osName = "Unknown";
}

我(几乎)确信这符合C++17规范,即if constexpr只在功能体中工作--但我的问题是:

Q1如何在C++1z/C++14中实现类似于if-constexpr的类和全局作用域?我不是在这里要求再解释一下模板的专业化.但是有类似于if constexpr一样简单的东西..。

Q2是否计划为上述作用域扩展C++?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-12-13 16:06:04

如何在C++1z/C++14中实现类似于函数类和全局作用域的if-constexpr效应?我不是在这里要求再解释一下模板的专业化.

基本上,你只是说,“我想要模板专业化,但没有所有讨厌的模板专门化。”

if constexpr是根据编译时构造改变函数行为的工具.模板专门化是C++为根据编译时构造更改定义提供的工具。它是C++为此功能提供的唯一工具。

现在,对于初始化变量的简单情况,您可以始终创建和调用lambda。C++17为lambda提供了constexpr支持,而lambda可以使用if constexpr来决定返回哪个值。

是否有计划将C++扩展到上述范围?

不是的。以下是所有的建议,而过去几年中没有人深入到这个领域。

他们不太可能会这么做。

票数 17
EN

Stack Overflow用户

发布于 2016-12-13 18:47:15

索引类型:

代码语言:javascript
复制
template<std::size_t I>
using index = std::integral_constant<std::size_t, I>;

first_truth获取一组编译时bools,并说明第一个编译时的索引是什么。如果您传递给它N个编译时bools,如果它们都是false,它将返回N:

代码语言:javascript
复制
constexpr index<0> first_truth() { return {}; }
template<class...Rest>
constexpr index<0> first_truth(std::true_type, Rest...) { return {}; }
template<class...Rest>
constexpr auto first_truth(std::false_type, Rest...rest) {
  return index<first_truth( rest... )+1>{};
}

dispatch接受一组编译时bools并返回lambda。此lambda通过完美转发与第一个真正编译时bool匹配的第一个元素返回:

代码语言:javascript
复制
template<class...Bools>
constexpr auto dispatch(Bools...bools) {
  constexpr auto index = first_truth(bools...);

  return [](auto&&...fs){
    return std::get< decltype(index){} >(
      std::forward_as_tuple( decltype(fs)(fs)... )
    );
  };
}

编译时bool类型:

代码语言:javascript
复制
template<bool b>
using bool_t = std::integral_constant<bool, b>;
template<bool b>
bool_t<b> bool_k{};

现在我们解决你的问题:

代码语言:javascript
复制
const char* const osName = 
  dispatch(
    bool_k<os == OS::Linux>,
    bool_k<os == OS::MacOs>,
    bool_k<os == OS::MsWindows>
  )(
    "Linux",
    "MacOS",
    "MS Windows",
    "Unknown"
  );

它应该近似于编译时开关。我们可以用更多的工作来更紧密地与争论联系在一起。

未编译的代码,可能包含tpyos。

票数 4
EN

Stack Overflow用户

发布于 2016-12-14 16:25:45

如何在编译时间常数w/o模板专业化的基础上定义不同类型?

下面是:

代码语言:javascript
复制
constexpr auto osPropsCreate()
{
    if constexpr (os == OS::Linux) {
        struct Props { const char* name; int props1; using handle = int; }; 
        return Props{"linux", 3};
    } else if constexpr (os == OS::MacOs) {
        struct Props { const char* name; using handle = float; }; 
        return Props{"mac"};
    } else if constexpr (os == OS::MsWindows) {
        struct Props { const char* name; using handle = int; }; 
        return Props{"win"};
    } else
        return;  
}

using OsProps = decltype(osPropsCreate());
constexpr OsProps osProps = osPropsCreate();

正如您所看到的--我使用新的构造if constexpr从某些“实现”函数中生成依赖于编译时常量的类型。它不像D语言中的static if那样容易使用--但它很有效--我可以这样做:

代码语言:javascript
复制
int linuxSpecific[osProps.props1];
int main() {
    std::cout << osProps.name << std::endl;
    OsProps::handle systemSpecificHandle;
}

下一步-根据编译时间常数定义不同的函数:

代码语言:javascript
复制
constexpr auto osGetNameCreate() {
    if constexpr (os == OS::Linux) {
        struct Definition {
            static constexpr auto getName() {
                return "linux";
            }
        };
        return Definition::getName;
    } else if constexpr (os == OS::MacOs) {
        // we might use lambda as well
        return [] { return "mac"; };
    } else if constexpr (os == OS::MsWindows) {
        struct Definition {
            static constexpr auto getName() {
                return "win";
            }
        };
        return Definition::getName;
    } else
        return;
}


constexpr auto osGetName = osGetNameCreate();

int main() {
    std::cout << osGetName() << std::endl;
} 

实际上,它们可以是类似函数的对象(函子),也可以是嵌套类中的静态成员函数。这并不重要--我们完全可以为不同的编译时间常数定义不同的东西(在本例中是OS类型)。注意,对于未知系统,我们只返回void -它将导致未知系统的编译错误.

回答第二个问题:

第一个答案为它提供了注释中的推理(链接)。我的解释是,C++标准委员会还没有准备好应对这一变化。也许与D竞争将是再次提出这个问题的好理由.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41118861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档