Click here to Skip to main content
15,891,864 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi all,
I am an hobbyist programmer used to write programs for windows in a C style script (liteC). I am recycling myself so I learn to use C++. I am building a little project in VS2017 for WIN32 with an old D3D9 engine and ImGui. I have no problems to understand what classes, namespaces and scopes are.

I am building a file browser with std::experimental::filesystem and everything went right until, suddenly, the compiler stopped recognizing its namespace. VS recognizes it and it does not show any inclusion/namespace problem, but in compilation time it refuses to recognize the 'std' namespace, which was perfectly recognized yesterday evening.

I use a shortcut like the following for the filesystem module included into the class implementation file:
C++
namespace fs = std::experimental::filesystem;


The error prompt:
Error	C2653	'fs': is not a class or namespace name	WMB7 Parser	g:\visual studio\wmb7 parser\wmb7 parser\filebrowser.h	22	


The error prompt when sustituting the namespace shortcut by the full namespace path:
Error	C3083	'experimental': the symbol to the left of a '::' must be a type	WMB7 Parser	g:\visual studio\wmb7 parser\wmb7 parser\filebrowser.h	22	
Error	C3083	'filesystem': the symbol to the left of a '::' must be a type	WMB7 Parser	g:\visual studio\wmb7 parser\wmb7 parser\filebrowser.h	22	


What could I have done to stop it from recognizing it? I am lost.

Thank you in advance.
Txes.

---------------------------------------------------------------------
UPDATE

Just noticed that everything works as expected when including the file system library into the main header instead of the class implementation file. Stunning...

---------------------------------------------------------------------

I am pretty sure that there are no systax errors in the source, but there you go anyway:

Main.h
C++
#pragma once

// Include the usual Windows headers
#define WIN32_LEAN_AND_MEAN		
#include <windows.h>

// Include D3D9
#include <d3d9.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>

// Include general standard library modules
#include <vector>
#include <string>

// Include ImGui
//#include "misc\freetype\imgui_freetype.h"
#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h"

// Include 3dgs data types, variables, and functions
#include "var.h"
#include "adll.h"

// 3dgs vars global pointer. Initialization on 'Core.cpp'
extern ENGINE_VARS *ev;

// Error message box
#define EBox(text) MessageBox(NULL, text, "CRITICAL_ERROR", 0);


FileBrowser.h
C++
#pragma once

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

	bool Init();
	void Close();

	bool GetFolderContent(const char *_chrRoot, const char *_chrFolder);
	bool Draw();

private:
	// Logical drives
	char *m_drives[33];
	char m_driveNames[99];
	long m_driveCount;
	long FindLogicalDrive(std::string _str);

	// Folder content
	fs::path m_pathRoot; // 22nd code line, the source of the unrecognized namespace
	fs::path m_pathFolder;
	std::vector<std::string> m_path;
	std::vector<std::string> m_content;

	// List box
	int m_current;
};


FileBrowser.cpp
C++
#include "Main.h"

#include <experimental/filesystem>
//#include <filesystem>
//#include <Knownfolders.h>
//#include <comdef.h> 

#include "FileBrowser.h"

namespace fs = std::experimental::filesystem;

// ------------------------------------------------------------------------------------------------------------

FileBrowser::FileBrowser() {
	m_driveCount = 0;
	m_path.reserve(16);
	m_content.reserve(64);
	m_current = -1;
}

FileBrowser::~FileBrowser() {
}

// ------------------------------------------------------------------------------------------------------------

bool FileBrowser::Init() {
	// Clear string vectors
	m_path.clear();
	m_content.clear();

	// Logical drives
	memset(m_drives, 0, sizeof(char*) * 33);
	DWORD _logicalDrives = GetLogicalDrives();
	m_driveCount = 0;

	char *_chrT = m_driveNames;
	for (char _l = 0; _l < 32; _l += 1) {
		if (!(_logicalDrives & (1 << _l)))
			continue;
		m_drives[m_driveCount] = _chrT;
		*_chrT = 65 + _l; // drive letter
		*(_chrT + 1) = 58; // doble point
		*(_chrT + 2) = NULL;
		_chrT += 3;
		m_driveCount += 1;
	}

	// Init folder content
	GetFolderContent("", fs::current_path().u8string().c_str());

	return true;
}

void FileBrowser::Close() {
	m_path.clear();
	m_content.clear();
}

bool FileBrowser::GetFolderContent(const char *_chrRoot, const char *_chrFolder) {
	m_pathRoot = fs::u8path(_chrRoot);
	m_pathFolder = fs::u8path(_chrFolder);
	fs::path _pathFull;

	// Build the full path
	if (*_chrRoot == NULL) {
		_pathFull = m_pathFolder;
	} else {
		_pathFull = m_pathRoot;
		_pathFull += "\\";
		_pathFull += m_pathFolder;
	}
	if (!fs::exists(_pathFull))
		return false;
	if (!fs::is_directory(_pathFull))
		return false;

	// 
	size_t _folderCount = 0;
	for (const fs::directory_entry& _p : fs::directory_iterator(_pathFull)) {
		const fs::path& _path = _p.path();

		// avoid system and hidden files
		DWORD _attb = GetFileAttributesW(_path.wstring().c_str());
		if (_attb & FILE_ATTRIBUTE_HIDDEN)
			continue;
		if (_attb & FILE_ATTRIBUTE_SYSTEM)
			continue;

		// save the filename of the current path
		if (fs::is_directory(_path)) {
			m_content.insert(m_content.begin() + _folderCount, _path.filename().u8string().c_str());
			_folderCount += 1;
		} else {
			m_content.push_back(_path.filename().u8string().c_str());
		}
	}

	// decompose the folder path to its members
	fs::path _pathFolder = m_pathFolder;
	do {
		const std::string _str = _pathFolder.filename().u8string().c_str();
		if(_str.find("\\") == std::string::npos)
			m_path.insert(m_path.begin(), _str);
		_pathFolder = _pathFolder.parent_path();
	} while (_pathFolder.has_filename());

	return true;
}

long FileBrowser::FindLogicalDrive(std::string _str) {
	for (long _i = 0; _i < m_driveCount; _i += 1) {
		if (_str.find(m_drives[_i]) == std::string::npos)
			continue;
		return _i;
	}
	return -1;
}

bool PathContentGetter(void *_data, int _index, const char **_label) {
	std::vector<std::string> *_content = (std::vector<std::string>*)_data;
	*_label = (*_content)[_index].c_str();
	return true;
}

bool FileBrowser::Draw() {
	float _width = ImGui::GetContentRegionAvailWidth();

	// ----- CURRENT PATH BUTTONS -----
	fs::path _pathFull = "";
	for (unsigned long _i = 0; _i < m_path.size(); _i += 1) {
		fs::path _path = fs::u8path(m_path[_i]);
		// If the root of the current path is a logical drive
		if (_path.has_root_name()) {
			long _drive = FindLogicalDrive(_path.u8string().c_str());
			if (_drive < 0) {
				EBox("Unknown error on logical drives search");
				return false;
			} else {
				if (ImGui::BeginCombo("##DrivesCombo", m_drives[_drive], ImGuiComboFlags_NoArrowButton)) {
					// loop through the logical drives array
					for (long _ii = 0; _ii < m_driveCount; _ii += 1) {
						bool _isSelected = (_ii == _drive);
						if (ImGui::Selectable(m_drives[_ii], &_isSelected, NULL)) {
							//m_pathRoot = "";
							//m_pathFolder = m_drives[_ii];
							//m_pathFolder += "\\";
							//GetFolderContent(m_pathRoot.u8string().c_str(), m_pathFolder.u8string().c_str());
							//m_current = -1;
							EBox(m_drives[_ii]);
						}
					}
					ImGui::EndCombo();
				} else {
					_pathFull = m_drives[_drive];
				}
			}
		} else { // if it is not the root of the path
			if (_i != 0) {
				_pathFull += "\\";
			}
			_pathFull += _path;
			if (ImGui::Button(_path.u8string().c_str(), ImVec2(0, 0))) {
				//_pathFull = _path;
				//GetFolderContent(m_pathRoot.u8string().c_str(), _pathFull.u8string().c_str());
				EBox(_pathFull.u8string().c_str());
			}
		}
	}

	// ----- CURRENT PATH CONTENT LIST BOX -----
	ImGui::PushItemWidth(_width);

	if (ImGui::ListBox("##PathContentList", &m_current, PathContentGetter, &m_content, m_content.size(), 6)) {
		EBox(m_content[m_current].c_str());

	}

	return true;
}


What I have tried:

- Use the full namespace instead of the shortcut.
- Declare the namespace in the class header. Something I read I should not.
- Restore yesterdays code.
- Restart the system and the IDE.
- Modify file inclusion order.
- Not get desperated xP
Posted
Updated 6-Mar-20 23:57pm
v6
Comments
Richard MacCutchan 6-Mar-20 7:24am    
"it refuses to recognize the 'std' namespace, which was perfectly recognized yesterday evening."
So what has changed between then and now? I have used that namespace on VS 2017 without problems.

And it would help if you just posted the relevant part of the code and the actual error message rather than dumping everything and expecting us to find where the error may have occurred.
txesmi 6-Mar-20 7:55am    
Thank you for your answer. I am sorry for the inconvenience.
The error code is: Error C2653 'fs': is not a class or namespace name WMB7 Parser g:\visual studio\wmb7 parser\wmb7 parser\filebrowser.h 22
There are more error lines, but all related to the ausence of the namespace recognition.

Nothing has changed. I restored the code which was compiling just fine yesterday.

Greets,
txes
Richard MacCutchan 6-Mar-20 7:40am    
Just checked my sample and it uses exactly that construct and builds fine.

You have the following statements in FileBrowser.cpp:
C++
#include "Main.h"
#include "FileBrowser.h"

#include <experimental/filesystem>

However, you are trying to use the fs namespace in FileBrowser.h, but it is not defined until after that header file has been processed. Change the order to
C++
#include "Main.h"

#include <experimental/filesystem>
#include "FileBrowser.h"

and it should work.
 
Share this answer
 
v3
Comments
txesmi 6-Mar-20 8:55am    
Thank you for your answer. I had already tried your solution and the same error came around. Tried it again anyway but same.

I am thinking on reinstalling the whole thing even though it makes me want to blow it all...

Thank you again. It is really apreciated.
Cheers!
Richard MacCutchan 6-Mar-20 9:36am    
Why would you do that? Investigate the problem carefully and correct your mistakes.

It is probably likely that you have the same issue with Main.h being included before filesystem. Make sure you put all system includes before any local includes/definitions.
txesmi 6-Mar-20 10:48am    
I came here because I had already exhausted all my knowledge around and google findings. I followed your advise and checked everything and ensured that "Main.h" is included first and each class header last, been each dependencies in the middle. The project is in its very beginning and I just squeezed it down so it has only declarations and class objects creations. No more. The graphics engine and the UI engine is completelly out. It has only three nested classes: Core -> UserInterface -> FileBrowser, and they only create the next class object declarated on each. Been a 'std::experimental::filesystem::path' object as the last in the chain.
Unfortunatelly, it does not compile and gives me the same error at the same place. I did change nothing in the project properties. The only thing I can think is that something has been corrupted in the way...
Stefan_Lang 6-Mar-20 10:14am    
Almost: it's still missing the declaration of the symbol fs.
txesmi 6-Mar-20 10:50am    
Hi, thank you for your answer.

Should I declare the namespace in the class header?
Always make sure every header file is self-sufficient. In this case, the header FileBrowser.h uses the following symbols which are not initially known to the compiler:

C++
std::string
std::vector
fs
std::experimental::filesystem


Any source file that includes this header will have to make sure that these symbols are supplied before including FileBrowser.h. This is very tedious and error prone, therefore it is much better to include all definitions right within the header file itself:

C++
#include <string>
#include <vector>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

class FileBrowser {
...

You can sometimes avoid to actually include other headers by just supplying forward declarations. But that only works as long as you don't have actual data members using these symbols: the compiler needs to at least know the size of each data member to compile the class definition.
 
Share this answer
 
v2
Comments
txesmi 6-Mar-20 11:04am    
Thank you very much!
At the end, it compiles.

I had read that I should not include files on class headers but it contradicts the solution. The world of self-learning is a narrow one.

Thank you again.
Greets!
Stefan_Lang 6-Mar-20 11:41am    
Well, yes, you should *avoid* including headers in a header file if you can. But here there is no other reasonable way. That's why I added that last paragraph.
txesmi 7-Mar-20 5:58am    
Just noticed that everything works as expected when including the file system library into the main header instead of the class implementation file. Stunning...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900