原始(a-la拼图)版本

我有这段输出0的代码:

#include <iostream>
#include <regex>

using namespace std;

regex sig_regex("[0-9]+");
bool oldmode = false;

template<class T>
struct B
{
    T bitset;

    explicit B(T flags) : bitset(flags) {}

    bool foo(T n, string s)
    {
        return bitset < 32                   // The mouth is not full of teeth
               && 63 > (~n & 255) == oldmode // Fooness holds
               && regex_match(s, sig_regex); // Signature matches
    }
};

template<class T>
struct D : B<T>
{
    D(T flags) : B<T>(flags) {}

};

int main()
{
    D<uint64_t> d(128 | 16 | 1);
    cout << d.foo(7, "123") << endl;
}

但是,当我将foo()函数从B移到D时,它开始输出1(proof is on Coliru)。

为什么会这样?

MCVE版本

Live on Coliru
#include <iostream>
#include <bitset>

using namespace std;

template<class T>
struct B
{
    T bitset{0};

    bool foo(int x)
    {
        return bitset < 32 && 63 > (x + 1) == x % 2;
    }
};

template<class T>
struct D : B<T>
{
    bool bar(int x) // This is identical to B<T>::foo()
    {
        return bitset < 32 && 63 > (x + 1) == x % 2;
    }
};

int main()
{
    D<uint64_t> d;
    cout << d.foo(1) << endl; // outputs 1
    cout << d.bar(1) << endl; // outputs 0; So how is bar() different from foo()?
}

最佳答案

这就是为什么你不应该using namespace std;

bool foo(T n, string s)
{
    return bitset < 32
           && 63 > (~n & 255) == oldmode
           && regex_match(s, sig_regex);
}

那个bitset不是您想的那样。因为B<T>是一个依赖的基类,所以从不合格的查找中隐藏了成员。因此,要访问bitset,您需要通过this 1对其进行访问,或对其进行显式限定(有关更多详细信息,请参见here):
(this->bitset)
B<T>::bitset

因为在派生的情况下bitset没有命名B<T>::bitset,这意味着什么?好吧,因为您编写了using namespace std;,实际上是std::bitset,其余的表达式恰好是有效的。这是发生了什么:
bool foo(T n, string s)
{
    return std::bitset<32 && 63>(~n & 255) == oldmode
           && regex_match(s, sig_regex);
}
32 && 63的计算结果为true,对于1u模板参数,该值提升为std::bitset。此std::bitset使用~n & 255初始化,并使用oldmode检查是否相等。最后一步是有效的,因为std::bitset具有一个非显式的构造函数,该构造函数允许从std::bitset<1>构造一个临时的oldmode

1注意,在这种情况下,由于一些非常清晰的解析歧义规则,我们需要在this->bitset上加上括号。有关详细信息,请参见Template dependent base member is not resolved properly

关于c++ - 将成员函数从基类移动到派生类不会明显破坏程序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40462612/

10-13 07:05