Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用traits访问编译时常量值?_C++_Templates - Fatal编程技术网

C++ 如何使用traits访问编译时常量值?

C++ 如何使用traits访问编译时常量值?,c++,templates,C++,Templates,我正在从事一个项目,其中某个函数的行为需要在几个值之间切换: class James{ public: James(){ if(a==0){ //do this }else{ // do that } } }; 当前,在运行时从配置文件中读取“a”。然而,实际上,“a”可以在编译时确定,而不是在运行时确定。我在考虑上一堂特质课 struct TraitZero{ conste

我正在从事一个项目,其中某个函数的行为需要在几个值之间切换:

class James{
public:
    James(){
        if(a==0){
            //do this
        }else{
            // do that
        }
    }
};
当前,在运行时从配置文件中读取“a”。然而,实际上,“a”可以在编译时确定,而不是在运行时确定。我在考虑上一堂特质课

struct TraitZero{
    constexpr int a = 0;
};

struct TraitOne{
    constexpr int a = 1;
};
然后将James转换为模板类

template<typename Trait>
class James{
    constexpr int a = Trait::a;
    public:
        James(){
            if(a=0){
                //do this
            }else{
                // do that
            }
        }
    };
模板
詹姆斯班{
constexpr int a=Trait::a;
公众:
詹姆斯(){
如果(a=0){
//这样做
}否则{
//那样做
}
}
};
我不知道我哪里弄错了,但这没有编译

我想知道这里是否有人曾经解决过这样的问题。任何人都可以分享一些见解吗?

为什么不在编译时使用-D选项传递a#define?
例如:

a
数据成员必须声明为
constepr
静态
,才能以您尝试使用它们的方式使用:

struct TraitZero{
    static constexpr int a = 0;
};

struct TraitOne{
    static constexpr int a = 1;
};
抛开它目前的格式不正确这一事实不谈,否则您将不能作为
Traits::a
访问它。
这同样适用于类
James

template<typename Trait>
class James{
    static constexpr int a = Trait::a;
    //...
};
即使您被允许修改
a
(并且您不是因为它是静态constexpr数据成员),在这种情况下,您也会将0分配给
a
,并不断获得
else
分支。
很可能您正在寻找相似但略有不同的东西:

if(a == 0){

下面是一个基于您的代码修复后的示例:

#include<iostream>

struct TraitZero{
    static constexpr int a = 0;
};

struct TraitOne{
    static constexpr int a = 1;
};

template<typename Trait>
class James{
static constexpr int a = Trait::a;
public:
    James(){
        if(a==0){
            std::cout << "0" << std::endl;
        }else{
            std::cout << "1" << std::endl;
        }
    }
};

int main() {
    James<TraitZero> j0;
    James<TraitOne> j1;
}
#包括
struct TraitZero{
静态constexpr int a=0;
};
结构TraitOne{
静态constexpr int a=1;
};
模板
詹姆斯班{
静态constexpr int a=Trait::a;
公众:
詹姆斯(){
如果(a==0){
std::coutAs,只有
静态
数据成员可以是
constepr
,您需要在条件中使用
==
而不是
=

这就是说,由于您希望在编译时确定
a
,因此在编译时基于
a
进行分支也可能对您有益。为此,您可以使用or(从C++17开始)


假设有以下三个特点

struct TraitZero{
    static constexpr int a = 0;
};

struct TraitOne{
    static constexpr int a = 1;
};

template<size_t N>
struct TraitN {
    static constexpr int a = N;
};
从这里可以看出,constexpr if可以用来创建比SFINAE更干净、更自然的代码,其优点是它仍然会在编译时而不是运行时进行评估;不幸的是,大多数编译器还不支持它。[在这个特定的例子中,
James()的每个版本
也将缩短一条机器指令(使用GCC 7.0编译时),因为没有使用伪参数来区分重载。]

更具体地说,对于constexpr if,如果条件为
true
,则放弃语句false,如果条件为
false
,则放弃语句true;实际上,这基本上意味着编译器将整个constexpr if语句视为要执行的分支。例如,在这种情况下,编译器将根据
Trait::a
的值,选择以下三个函数之一

// If Trait::a == 0:
James() {
    std::cout << "Trait::a is 0.\n";
}

// If Trait::a == 1:
James() {
    std::cout << "Trait::a is 1.\n";
}

// If Trait::a == anything else:
James() {
    std::cout << "Trait::a is neither 0 nor 1.\n";
}
每个类型的构造函数都将被专门编码以输出适当的行,并且三个构造函数中没有一个实际包含任何分支


请注意,出于个人喜好,我只将成员
a
标记为不必要;因为我可以直接访问
Trait::a
,所以我更愿意这样做,所以如果我放弃了,我就不必检查
a
是什么。如果你愿意,或者其他地方需要,请随意使用它。

a=0
应该是
a==0
你知道吗意思是a==0?结构中不需要
constexpr int a
静态的
?是否愿意分享编译错误?顺便说一句,你不必使用traits类。你可以简单地直接在整数上模板
James
。直接在布尔或枚举上模板是很常见的,特别是为了控制行为。如果你这样做的话nk你需要更多的东西一个traits类很好,但是如果你只需要一两个编译时布尔值,YAGNI.yes,==而不是=,我现在被CLion宠坏了
template<typename Trait>
class James {
    // Unnecessary, we can access Trait::a directly.
    //static constexpr int a = Trait::a;
  public:
    template<bool AZero = Trait::a == 0>
    James(std::enable_if_t<AZero, unsigned> = 0) {
        std::cout << "Trait::a is 0.\n";
    }

    template<bool AOne = Trait::a == 1>
    James(std::enable_if_t<AOne, int> = 0) {
        std::cout << "Trait::a is 1.\n";
    }

    template<bool ANeither = (Trait::a != 0) && (Trait::a != 1)>
    James(std::enable_if_t<ANeither, long> = 0) {
        std::cout << "Trait::a is neither 0 nor 1.\n";
    }
};
template<typename Trait>
class James {
    // Unnecessary, we can access Trait::a directly.
    //static constexpr int a = Trait::a;
  public:
    James() {
        if constexpr (Trait::a == 0) {
            std::cout << "Trait::a is 0.\n";
        } else if constexpr (Trait::a == 1) {
            std::cout << "Trait::a is 1.\n";
        } else {
            std::cout << "Trait::a is neither 0 nor 1.\n";
        }
    }
};
// If Trait::a == 0:
James() {
    std::cout << "Trait::a is 0.\n";
}

// If Trait::a == 1:
James() {
    std::cout << "Trait::a is 1.\n";
}

// If Trait::a == anything else:
James() {
    std::cout << "Trait::a is neither 0 nor 1.\n";
}
int main() {
    James<TraitZero> j0;
    James<TraitOne>  j1;
    James<TraitN<2>> j2;
}
Trait::a is 0.
Trait::a is 1.
Trait::a is neither 0 nor 1.