I would like to put the implementation of the specializations of a templated function to a separate source file, but if I try to call it (in MyAction), I get this error:
Explicit specialization has already been instantiated
I have no idea, why I get this error.
Example code:
main.cpp
#include <iostream>
#include <string>
#include "MyClass.h"
int main()
{
std::cout << "Hello, " << XX::MyClass().MyMethod<1>() << std::endl;
std::cin.get();
}
MyClass.h
#pragma once
#include <string>
namespace XX {
struct MyClass {
std::string MyAction() {
return MyMethod<0>() + MyMethod<1>();
}
template<int>
std::string MyMethod();
};
template<>
std::string MyClass::MyMethod<0>();
template<>
std::string MyClass::MyMethod<1>();
}
MyClass.cpp
#include "MyClass.h"
namespace XX {
template<>
std::string MyClass::MyMethod<0>() {
return "FOO";
}
template<>
std::string MyClass::MyMethod<1>() {
return "BAR";
}
}
Is there a template instantiation rule, which I am not aware of?
Ok looks like problem is an order.
When you are defining MyAction compiler tries instantiate template, but he doesn't know about specialization.
When you declare MyAction and define it in cpp after template specialization it will work.
// header part
#include <string>
namespace XX {
struct MyClass {
template<int>
std::string MyMethod();
std::string MyAction();
};
}
// cpp part
namespace XX {
template<>
std::string MyClass::MyMethod<0>() {
return "a";
}
template<>
std::string MyClass::MyMethod<1>() {
return "b";
}
std::string MyClass::MyAction() {
return MyMethod<0>() + MyMethod<1>();
}
}
See here: https://godbolt.org/z/aGSB21
Note if you move MyClass::MyAction() above MyClass::MyMethod<1>() error will come back.
Here is version where specialization is can be declared in header file: https://godbolt.org/z/kHjlne
Related
The following compiles fine (on g++ 8.3.0-6 and --std=c++17) with the std::stringstream being a non-static class member:
#include <iostream>
#include <sstream>
class Foo {
public:
std::stringstream ss;
};
int main() {
Foo f;
f.ss << "bar\n";
std::cout << f.ss.str();
}
But the following doesn't (same compiler, same options), where the stringstream is static inline:
#include <iostream>
#include <sstream>
class Foo {
public:
static inline std::stringstream ss;
};
int main() {
Foo::ss << "bar\n";
std::cout << Foo::ss.str();
}
My compiler tells me that std::stringstream has no default constructor, which it actually should:
error: no matching function for call to ‘std::__cxx11::basic_stringstream<char>::basic_stringstream()’
static inline std::stringstream ss;
^~
What am I doing wrong here?
This is almost certainly a compiler bug. It is a little strange that the compiler knows about the constructor overload in one case but not the other, though it might have something to do with the constructor being explicit.
This does compile with 8.3:
#include <iostream>
#include <sstream>
class Foo {
public:
static inline std::stringstream ss{};
}; //^^
int main() {
Foo::ss << "bar\n";
std::cout << Foo::ss.str();
}
PS: Also this answer comes to the conclusion that explicit is the cause https://stackoverflow.com/a/47782995/4117728.
What must the structure of a class look like if it is defined in a separate namespace?
Which parts belong in the header file and which in the cpp file?
How can I make the class accessible only through this specific namespace?
classname.h
#include <iostream>
namespace N {
class classname {
public:
void classmethod();
}
}
classname.cpp
#include "classname.h"
namespace N {
void classname::classmethod() {
std::cout << "classmethod" << std::endl;
}
}
main.cpp
#include "classname.h"
int main() {
N::classname a;
classname b; // Error!
a.classmethod();
return 0;
}
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).
I am trying to use forward declarations in header files to reduce the number of #include used and hence reduce dependencies when users include my header file.
However, I am unable to forward declare where namespaces are used. See example below.
File a.hpp:
#ifndef __A_HPP__
#define __A_HPP__
namespace ns1 {
class a {
public:
a(const char* const msg);
void talk() const;
private:
const char* const msg_;
};
}
#endif //__A_HPP__
File a.cpp:
#include <iostream>
#include "a.hpp"
using namespace ns1;
a::a(const char* const msg) : msg_(msg) {}
void a::talk() const {
std::cout << msg_ << std::endl;
}
File consumer.hpp:
#ifndef __CONSUMER_HPP__
#define __CONSUMER_HPP__
// How can I forward declare a class which uses a namespace
//doing this below results in error C2653: 'ns1' : is not a class or namespace name
// Works with no namespace or if I use using namespace ns1 in header file
// but I am trying to reduce any dependencies in this header file
class ns1::a;
class consumer
{
public:
consumer(const char* const text) : a_(text) {}
void chat() const;
private:
a& a_;
};
#endif // __CONSUMER_HPP__
Implementation file consumer.cpp:
#include "consumer.hpp"
#include "a.hpp"
consumer::consumer(const char* const text) : a_(text) {}
void consumer::chat() const {
a_.talk();
}
Test file main.cpp:
#include "consumer.hpp"
int main() {
consumer c("My message");
c.chat();
return 0;
}
UPDATE:
Here is my very contrived working code using the answer below.
File a.hpp:
#ifndef A_HPP__
#define A_HPP__
#include <string>
namespace ns1 {
class a {
public:
void set_message(const std::string& msg);
void talk() const;
private:
std::string msg_;
};
} //namespace
#endif //A_HPP__
File a.cpp:
#include <iostream>
#include "a.hpp"
void ns1::a::set_message(const std::string& msg) {
msg_ = msg;
}
void ns1::a::talk() const {
std::cout << msg_ << std::endl;
}
File consumer.hpp:
#ifndef CONSUMER_HPP__
#define CONSUMER_HPP__
namespace ns1
{
class a;
}
class consumer
{
public:
consumer(const char* text);
~consumer();
void chat() const;
private:
ns1::a* a_;
};
#endif // CONSUMER_HPP__
File consumer.cpp:
#include "a.hpp"
#include "consumer.hpp"
consumer::consumer(const char* text) {
a_ = new ns1::a;
a_->set_message(text);
}
consumer::~consumer() {
delete a_;
}
void consumer::chat() const {
a_->talk();
}
File main.cpp:
#include "consumer.hpp"
int main() {
consumer c("My message");
c.chat();
return 0;
}
To forward declare class type a in a namespace ns1:
namespace ns1
{
class a;
}
To forward declare a type in multiple level of namespaces:
namespace ns1
{
namespace ns2
{
//....
namespace nsN
{
class a;
}
//....
}
}
Your are using a a member of consumer which means it needs concrete type, your forward declaration won't work for this case.
For nested namespaces, since C++17, you can do
namespace ns1::ns2::nsN
{
class a;
}
Apart to forward-declare the class from within its namespace (as #billz says), remember to either use (prepend) that namespace when referring to the forward-declared class, or add a using clause:
// B.h
namespace Y { class A; } // full declaration of
// class A elsewhere
namespace X {
using Y::A; // <------------- [!]
class B {
A* a; // Y::A
};
}
Ref: Namespaces and Forward Class Declarations
Please excuse me but I didn't know to give a name to the title in a short way.
Why do I need to declare an overloaded operator inside the header to make it work in this example:
HEAD.H
#pragma once
namespace test {
class A {
public:
A() : x(0) {}
int x;
};
A& operator++(A& obj); //this is my question
}
HEAD.CPP
#include "head.h"
namespace test {
A& operator++(A& obj) {
++obj.x;
return obj;
}
}
MAIN.CPP
#include <iostream>
#include "head.h"
using namespace std;
using namespace test;
int main() {
A object;
++object; //this won't work if we delete declaration in a header
return 0;
}
operator++ is defined and declared in a namespace inside "head.cpp" so why do I need to declare it one more time in a header?
Thank you.
The CPP files are compiled independently of each other, and they only see the header files they've included (which are in fact textually added to the source code of the CPP before compilation). As such you'll use the header file to inform the compiler that a function exists with that signature (be it an operator overload).
Then the output from your CPP files is put together by the linker, which is when you'd find out if for instance you had declared a function in a header file but never taken the trouble to implement it.
Simple example with namespaces:
#include <iostream>
namespace test{
int f() { return 42; }
int g() { return -1; }
}
namespace other{
int f() { return 1024; }
}
using namespace other;
int main(){
//error: 'g' was not declared in this scope
//std::cout << g() << std::endl;
std::cout << test::f() << std::endl; //42
std::cout << f() << std::endl; //1024
return 0;
}