类中没有成员命名:if else 语句的两个路径都应在编译时可编译。

huangapple go评论83阅读模式
英文:

No member named in class: Both paths of the if else statement should be compilable at compile time

问题

我正在使用C++编写一个缓存模型。模型包括一些级别的缓存(Cache类)和主内存(Memory类)。一个Cache要么由另一个Cache支持,要么由Memory支持。例如:

Cache l1 ---支持于---> Cache l2 ---支持于---> Memory memory

当调用l1.readFromCache()时,如果l1由另一个Cache(例如l2)支持,它将调用l2.readFromCache(),否则将调用l2.readFromMemory()。在上面的图示中,期望出现以下顺序:

l1.readFromCache()调用l2.readFromCache(),然后l2.readFromCache()调用memory.readFromMemory()

以下是代码:

#include <iostream>

class Memory
{
public:
    unsigned long readFromMemory(unsigned long address)
    {
        (void)address;
        std::cout << "readFromMemory() from Memory" << std::endl;
        return 100;
    }
};

template <class T>
class Cache
{
public:
    Cache(const std::string& name, T* cache, bool exclusive, bool writeback) :
        name{ name }, backedByCache{ true }, cache{ cache }, exclusive{ exclusive }, writeback{ writeback }, memory{} {}

    Cache(const std::string& name, Memory* memory) :
        name{ name }, backedByCache{ false }, cache{}, exclusive{ false }, writeback{ false }, memory{ memory } {}

    unsigned long readFromCache(unsigned long address)
    {
        std::cout << "readFromCache() from Cache " << name << std::endl;
        if (backedByCache) {
            std::cout << name << " is backed by a cache" << std::endl;
            return cache->readFromCache(address); /**** 错误 ****/
        }
        else {
            std::cout << name << " is backed by a memory" << std::endl;
            return memory->readFromMemory(address);
        }
        return 100;
    }

private:
    const std::string name;
    const bool backedByCache;
    T* cache;
    bool exclusive;
    bool writeback;
    Memory* memory;
};

int main()
{
    Memory memory;

    using L2Cache = Cache<Memory>;
    L2Cache l2{ "L2", &memory };

    using L1Cache = Cache<L2Cache>;
    L1Cache l1{ "L1", &l2, true, true };

    l1.readFromCache(0x80000000);

    return 0;
}

当我执行上面的代码时,无论是g++(11.3.1)还是clang++(16.0.6),都会在return cache->readFromCache(address);这一行抛出相同的错误:

main.cc:29:39: error: no member named 'readFromCache' in 'Memory'
                        return cache->readFromCache(address);
                               ~~~~~  ^
main.cc:29:39: note: in instantiation of member function 'Cache<Memory>::readFromCache' requested here
main.cc:56:12: note: in instantiation of member function 'Cache<Cache<Memory>>::readFromCache' requested here
        l1.readFromCache(0x80000000);

模板类Cache有两个构造函数,一个接受指向另一个Cache的指针T以及两个布尔值,另一个接受指向Memory类的指针。有一个布尔数据成员(backedByCache)用于跟踪缓存是由Cache还是Memory支持。通过这种方式,我可以轻松扩展模型以包含更多级别。我希望在运行该程序时看到以下输出:

readFromCache() from Cache L1
L1 is backed by a cache
readFromCache() from Cache L2
L2 is backed by a memory
readFromMemory() from Memory

我不知道为什么编译器会抱怨Memory中没有readFromCache(),因为if (backedByCache)应该选择适当的读取方法来自适当的指针。我已尝试使用shared_ptr和unique_ptr,但问题仍然存在。有人能帮我解释出错的原因并指出我的错误吗?

非常感谢。

英文:

I'm writing a cache model using C++. The model consists of some level of caches (the Cache class) and a main memory (the Memory class). A Cache is backed by either another Cache or a Memory. For example:

Cache l1 ---backed by---&gt; Cache l2 ---backed by---&gt; Memory memory

When l1.readFromCache() is called, if l1 is backed by another Cache (l2 for example), it will call l2.readFromCache(), otherwise, l2.readFromMemory() is called. In the above diagram, this sequence is expected:

l1.readFromCache() calls l2.readFromCache(), then l2.readFromCache() calls memory.readFromMemory()

Here is the code:

#include &lt;iostream&gt;

class Memory
{
public:
    unsigned long readFromMemory(unsigned long address)
    {
        (void)address;
        std::cout &lt;&lt; &quot;readFromMemory() from Memory&quot; &lt;&lt; std::endl;
        return 100;
    }
};

template &lt;class T&gt;
class Cache
{
public:
    Cache(const std::string&amp; name, T* cache, bool exclusive, bool writeback) :
        name{ name }, backedByCache{ true }, cache{ cache }, exclusive{ exclusive }, writeback{ writeback }, memory{} {}

    Cache(const std::string&amp; name, Memory* memory) :
        name{ name }, backedByCache{ false }, cache{}, exclusive{ false }, writeback{ false }, memory{ memory } {}

    unsigned long readFromCache(unsigned long address)
    {
        std::cout &lt;&lt; &quot;readFromCache() from Cache &quot; &lt;&lt; name &lt;&lt; std::endl;
        if (backedByCache) {
            std::cout &lt;&lt; name &lt;&lt; &quot; is backed by a cache&quot; &lt;&lt; std::endl;
            return cache-&gt;readFromCache(address); /**** ERRORRRRRRR ****/
        }
        else {
            std::cout &lt;&lt; name &lt;&lt; &quot; is backed by a memory&quot; &lt;&lt; std::endl;
            return memory-&gt;readFromMemory(address);
        }
        return 100;
    }

private:
    const std::string name;
    const bool backedByCache;
    T* cache;
    bool exclusive;
    bool writeback;
    Memory* memory;
};

int main()
{
    Memory memory;

    using L2Cache = Cache&lt;Memory&gt;;
    L2Cache l2{ &quot;L2&quot;, &amp;memory };

    using L1Cache = Cache&lt;L2Cache&gt;;
    L1Cache l1{ &quot;L1&quot;, &amp;l2, true, true };

    l1.readFromCache(0x80000000);

    return 0;
}

When I execute the code above, both g++ (11.3.1) and clang++ (16.0.6) throw the same error at line return cache-&gt;readFromCache(address);

main.cc:29:39: error: no member named &#39;readFromCache&#39; in &#39;Memory&#39;
return cache-&gt;readFromCache(address);
~~~~~  ^
main.cc:29:39: note: in instantiation of member function &#39;Cache&lt;Memory&gt;::readFromCache&#39; requested here
main.cc:56:12: note: in instantiation of member function &#39;Cache&lt;Cache&lt;Memory&gt;&gt;::readFromCache&#39; requested here
l1.readFromCache(0x80000000);

The templated class Cache has two constructors, one accepts a pointer T to another Cache and two booleans, the other one accepts a pointer to the Memory class. There is a boolean data member (backedByCache) to track if the cache is backed by a cache or a memory. By this way, I can expand the model to more levels easily. I expect to see these lines when I run that program:

readFromCache() from Cache L1
L1 is backed by a cache
readFromCache() from Cache L2
L2 is backed by a memory
readFromMemory() from Memory

I don't know why compiler complain about readFromCache() not in Memory since if (backedByCache) should choose the appropriate read method from the appropriate pointer. I have tried with shared_ptr and unique_ptr but the issue still the same.

Can anyone help me explain what was wrong and correct me if any.

Thank you very much.

答案1

得分: 1

问题:

backedByCache 在运行时确定执行 iftrue路径)或 elsefalse路径)块,但两个路径都必须编译。
因此,即使 backedByCachefalse,编译器仍然尝试编译 if true 路径,并生成您遇到的错误。

解决方案:

C++17 提供了 if constexpr,它指示编译器根据条件仅编译其中一个路径。
但在这种情况下,条件必须是编译时常量,因此不能使用成员(即使是 const 成员)。

而是可以使用**bool 模板参数**:

//-----------------vvvvvvvvvvvvvvvvvv-
template <class T, bool backedByCache>
class Cache
{
public:

    // ...

    unsigned long readFromCache(unsigned long address)
    {
        std::cout << "readFromCache() from Cache " << name << std::endl;
        //-vvvvvvvvv----------------
        if constexpr (backedByCache) 
        {
            std::cout << name << " is backed by a cache" << std::endl;
            return cache->readFromCache(address); /**** ERRORRRRRRR ****/
        }
        else 
        {
            std::cout << name << " is backed by a memory" << std::endl;
            return memory->readFromMemory(address);
        }
        return 100;
    }
}

创建对象需要额外的模板参数,例如:

//----------------------------vvvvv--
using L2Cache = Cache<Memory, false>;
L2Cache l2{ "L2", &memory };

完整演示(Godbolt)

英文:

The Problem:

backedByCache determines the execution of either the if (true path) or the else (false path) block in runtime, but both paths must be compiled.
Therefore even if backedByCache is false the compiler attempts to compile the if true path and issues the error you get.

A Solution:

C++17 offers if constexpr, which instructs the compiler to compile only one of the paths, depending on the condition.
However in this case the condition must be a compile time constant, and therefore a member (even a const one) cannot be used.

Instead you can use a bool template parameter:

//-----------------vvvvvvvvvvvvvvvvvv-
template &lt;class T, bool backedByCache&gt;
class Cache
{
public:
// ...
unsigned long readFromCache(unsigned long address)
{
std::cout &lt;&lt; &quot;readFromCache() from Cache &quot; &lt;&lt; name &lt;&lt; std::endl;
//-vvvvvvvvv----------------
if constexpr (backedByCache) 
{
std::cout &lt;&lt; name &lt;&lt; &quot; is backed by a cache&quot; &lt;&lt; std::endl;
return cache-&gt;readFromCache(address); /**** ERRORRRRRRR ****/
}
else 
{
std::cout &lt;&lt; name &lt;&lt; &quot; is backed by a memory&quot; &lt;&lt; std::endl;
return memory-&gt;readFromMemory(address);
}
return 100;
}
}

Creating an object requires an additional template argument, e.g.:

//----------------------------vvvvv--
using L2Cache = Cache&lt;Memory, false&gt;;
L2Cache l2{ &quot;L2&quot;, &amp;memory };

Full demo (Godbolt)

huangapple
  • 本文由 发表于 2023年7月24日 18:24:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753549.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定