简体   繁体   中英

Incomplete declaration of a partially specialized template

I am trying to partially specialize the std::hash struct for my own class TestHandle , and this class has its implementation split up using the opaque pointer idiom. So I am trying to provide the impl class with its own std::hash specialization. But I am running into templating problems.

Could someone help me understand why this is happening? I have attached all the necessary code below.

TestHandle.h

#pragma once
#include <memory>

class TestHandle {
public:
    TestHandle();

    void print();

    class Impl;
    std::unique_ptr<Impl> implementation;
};

TestHandle.cpp

#include "TestHandle.h"
#include "Impl.h"
#include <iostream>
using std::cout;
using std::endl;

TestHandle::TestHandle() : implementation{new TestHandle::Impl} { }

void TestHandle::print() {
    this->implementation->print();
    cout << "Hash of this->implementation is " 
        << std::hash<TestHandle::Impl>()(*this->implementation) << endl;
}

Impl.h

#pragma once
#include "TestHandle.h"
#include <functional>

class TestHandle::Impl {
public:

    void print();
    int inner_integer;
};

namespace std {
    template <> struct std::hash<TestHandle::Impl>;
}

Impl.cpp

#include "TestHandle.h"
#include "Impl.h"
#include <iostream>
using std::cout;
using std::endl;
#include <functional>

namespace std {
    template <> struct hash <TestHandle::Impl> {
        size_t operator() (const TestHandle::Impl& implementation) {
            return std::hash<int>()(implementation.inner_integer);
        }
    };
}

void TestHandle::Impl::print() {
    cout << "Printing from impl" << endl;
}

I am compiling with the following command

g++ -std=c++14 -c Impl.cpp TestHandle.cpp

and am getting the following error

TestHandle.cpp:11:12: error: invalid use of incomplete type 'std::hash<TestHandle::Impl>'
<< std::hash<TestHandle::Impl>()(*this->implementation) << endl; 
template <> struct std::hash<TestHandle::Impl>;

Just forward declares the specialisation. It doesn't have to implement all the method (or any) of the original template. The compiler has no idea about the operator() .

You will need to define the struct (in place of just the declaration);

template <> struct hash <TestHandle::Impl> {
        size_t operator() (const TestHandle::Impl& implementation) const noexcept;
    };

Side note: you will also need to provide the primary template (via inclusion) of <functional> (missing in the original listed code).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM