c++ - 是否可以将 CRTP 与本身模板化的派生类一起使用?

标签 c++ templates singleton crtp

我正在尝试将 CRTP 与派生类一起使用,这些派生类本身是模板化的,但遇到了我不知道如何修复的编译器错误。

有没有办法做我想做的事?

代码在这里。

#include <iostream>

// Parent class to use in CRTP
template <typename T>
class Singleton {
    public:

    static T& getInstance() {
        Protector p;
        static T instance(p);
        return instance;
    }

    // Singleton pattern - no copying!
    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    const Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;

protected: // so only derived classes can construct Singletons
    Singleton() = default;
    struct Protector {};    // avoids having to make Singleton a friend of descendents.
    virtual ~Singleton() = default;
};


// Simple example of using the CRTP, this one compiles and runs as expected
class Counter final : public Singleton<Counter> {
    private:
        int _counter;
    public:
        Counter (Protector) : _counter(0) {std::cout << "Counter Constructor" << std::endl;}
        ~Counter () {std::cout << "Counter Destructor" << std::endl;}
        int inc() {return ++_counter;}
        int dec() {return --_counter;}
        const int operator()() const {return _counter;}
};

// More complex example of using the CRTP. It generates compiler errors
template <typename T>
class TCounter final : public Singleton<TCounter<T>> {
    private:
        T _counter;
    public:
        TCounter (Protector) : _counter(0) {std::cout << "TCounter Constructor" << std::endl;}
        ~TCounter() {std::cout << "TCounter Destructor" << std::endl;}
        T inc() {return ++_counter;}
        T dec() {return --_counter;}
        const T operator()() const {return _counter;}
};

int main () {
    using namespace std;
    Counter& ctr = Counter::getInstance();
    cout << ctr() << ", " << ctr.inc() << ", " << ctr.dec() << endl;

    using FCounter = TCounter<float>;
    FCounter& fctr = FCounter::getInstance();
    cout << fctr() << ", " << fctr.inc() << ", " << fctr.dec() << endl;
    return 0;
}

这里是编译输出

$ g++ src/goof.cpp -o goof
src/goof.cpp:45:22: error: function definition does not declare parameters
   TCounter (Protector) : _counter(0) {std::cout << "TCounter Constructor" << std::endl;}
                      ^
src/goof.cpp: In instantiation of ‘static T& Singleton<T>::getInstance() [with T = TCounter<float>]’:
src/goof.cpp:58:29:   required from here
src/goof.cpp:10:12: error: no matching function for call to ‘TCounter<float>::TCounter(Singleton<TCounter<float> >::Protector&)’
   static T instance(p);
            ^~~~~~~~
src/goof.cpp:41:7: note: candidate: ‘TCounter<float>::TCounter()’
 class TCounter final : public Singleton<TCounter<T>> {
       ^~~~~~~~
src/goof.cpp:41:7: note:   candidate expects 0 arguments, 1 provided

我不明白的地方:

  • 为什么编译器认为候选构造函数采用零参数? (第 41 行)
  • 它提示我没有提供参数(第 45 行),但当我这样做时,它会输出不同的错误 - 期望在 Protector 之后有一个“)”。

预先感谢您的帮助。

最佳答案

您需要做的就是用手轻轻地引导编译器告诉它如何解析Protector

template <typename T>
class TCounter final : public Singleton<TCounter<T>> {
public:
  using Protector = typename Singleton<TCounter<T>>::Protector;
};

关于c++ - 是否可以将 CRTP 与本身模板化的派生类一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58697483/

相关文章:

c++ - 继承和对象的单例或静态数组

java - Spring 中的作用域代理是什么?

c# - SWIG 和 C# : insert empty C# class

c++ - 将 PySide 对象传递给 C++

javascript - 在Firefox中拖动图片时,如何做到没有 "Ghost"?

c++ - 如何在 C++11 中输出枚举类的值

java - 获取同一 Java 应用程序的实例(如果该应用程序已在运行)

c++ - 为什么我的全局 new() 覆盖被绕过?

c++ - 如何解开 C++ lambda 的错位名称?

c++ - gcc 返回嵌套类错误