-2

So in my Visual Studio solution I'm making a library and I have two Visual Studio projects, one for the library and one for the sandbox. In the library I'm trying to use forward declarations to create a class. What I'm simply doing in this example is creating a header file for my class, declaring std::string with the following forward declaration and creating a member pointer with that class.

Library project:

ClassFromLibrary.h

#pragma once

namespace std {
class string;
}

class ClassFromLibrary {
public:
ClassFromLibrary();
~ClassFromLibrary();

std::string* forwardDeclaredString;
};

ClassFromLibrary.cpp

#include "ClassFromLibrary.h"
#include <string>

ClassFromLibrary::ClassFromLibrary() 
: forwardDeclaredString(new std::string("Hello, world!"))
{
}

ClassFromLibrary::~ClassFromLibrary()
{
}

Sandbox project

main.cpp

#include <Library/ClassFromLibrary.h>
#include <iostream>

int main() 
{
    ClassFromLibrary test;
    std::cout << 
       *test.forwardDeclaredString //Root of the problem
                 << std::endl;
    std::cin.get();
}

The problem

As I said earlier, the library project compiles perfectly. However, the error which I mentioned in the title shows up when the forward declared member variable is referenced in any file from the sandbox project. I have a larger project where I get the same error, and the reason I want to achieve this is because I am using other external libraries within my library project, and when I create applications with it I don't want to have to put all the library include directories in the project properties, only the one for my library.

Thanks in advance!

  • What, exactly, do you expect to happen on that line? I'm surprised it fails to compile, I expect `std::ostream& << void*` would be picked. – Yakk - Adam Nevraumont Jan 25 '19 at 19:40
  • @user463035818 This is how you forward declare classes from a namespace. – Alan Rostem Jan 25 '19 at 19:40
  • other than redecalring the std string and the cout< – Spinkoo Jan 25 '19 at 19:43
  • @Yakk - Adam Nevraumont I expect it to print out the memory address, or if I de-reference it I expect to see the string be printed, but I can't build obviously. – Alan Rostem Jan 25 '19 at 19:44
  • well I know that this is how you forward declare a class. I am just surprised to see it for a type from `std` and I never would have expected this to be allowed. btw deleted the comment, because I was puzzled by that line, wrote the comment and only then realized that the whole question is about the forward declaration – 463035818_is_not_an_ai Jan 25 '19 at 19:45
  • "I don't want to have to put all the library include directories in the project properties, only the one for my library." not really sure what you mean, imho its a questionable motivation. You dont have to configure the project to include ``, do you? i mean its part of the standard library – 463035818_is_not_an_ai Jan 25 '19 at 19:48
  • 1
    @Yakk-AdamNevraumont it can't compile. It conflicts with normal string. And it is undefined behavior. – SergeyA Jan 25 '19 at 19:50
  • related/dupe: https://stackoverflow.com/questions/307343/forward-declare-an-stl-container – 463035818_is_not_an_ai Jan 25 '19 at 19:50
  • @user463035818 You're focusing too much on the fact that it is a std::string object in this example. I only used that class as an example of something I could forward declare, that std::string could be anything, just as long as it is from another library that isn't mine. – Alan Rostem Jan 25 '19 at 19:51
  • 1
    @AlanRostem we focus on the example you have provided. It is on you to provide MCVE. – SergeyA Jan 25 '19 at 19:52
  • not I am not focusing too much on that, this is the crucial point. You are simply not allowed to mess around with the `std` namespace (apart from specializations) – 463035818_is_not_an_ai Jan 25 '19 at 19:52

1 Answers1

2

You know that putting names in namespace std makes program ill-formed (except for some cases?)? Well, know you know why. The bug you have is a symptom of undefined behavior.

In my test, the way you declared your forward declaration in std is not how it is actually declared in string header. Yet it's a same name, so now you have name conflict (you have it as soon as you include iostream, which includes string. This is what my compiler is telling me when I am try compile your code:

/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/basic_string.h:6628:17: error: reference to 'string' is ambiguous

struct hash<string>

This is different from the error you put in the question, but since the behavior is undefined, anything can happen.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Maybe I should change my question, because I see now I'm getting the same error as you do. The problem I wanted to reproduce as not with string itself, but with a different class from a different library that I linked with my own library. – Alan Rostem Jan 25 '19 at 19:55
  • @AlanRostem that's why MCVE is a king. Do not change the question, because it is already answered. Instead, ask a new one. – SergeyA Jan 25 '19 at 20:00