I'm using CRTP design pattern to implement logging mechanism for my project. Base CRTP class looks like this:
#include <fstream>
#include <memory>
#include <mutex>
#include <iostream>
#include <sstream>
template <typename LogPolicy>
class Logger
{
public:
template <typename... Args>
void operator()(Args... args)
{
loggingMutex.lock();
putTime();
print_impl(args...);
}
void setMaxLogFileSize(unsigned long maxLogFileSizeArg)
{
//if (dynamic_cast<FileLogPolicy *>(policy.get()))
// policy->setMaxLogFileSize(maxLogFileSizeArg);
}
~Logger()
{
print_impl(END_OF_LOGGING);
}
protected:
std::stringstream buffer;
std::mutex loggingMutex;
std::string d_time;
private:
static constexpr auto END_OF_LOGGING = "***END OF LOGGING***";
void putTime()
{
time_t raw_time;
time(&raw_time);
std::string localTime = ctime(&raw_time);
localTime.erase(std::remove(localTime.begin(), localTime.end(), '\n'), localTime.end());
buffer << localTime;
}
template <typename First, typename... Rest>
void print_impl(First first, Rest... rest)
{
buffer << " " << first;
print_impl(rest...);
}
void print_impl()
{
static_cast<LogPolicy*>(this)->write(buffer.str());
buffer.str("");
}
};
One of the concrete logging class is logging to file, which looks like this:
#include "Logger.hpp"
class FileLogPolicy : public Logger<FileLogPolicy>
{
public:
FileLogPolicy(std::string fileName) : logFile(new std::ofstream)
{
logFile->open(fileName, std::ofstream::out | std::ofstream::binary);
if (logFile->is_open())
{
std::cout << "Opening stream with addr " << (logFile.get()) << std::endl;
}
}
void write(const std::string content)
{
std::cout << "Writing stream with addr " << (logFile.get()) << std::endl;
(*logFile) << " " << content << std::endl;
loggingMutex.unlock();
}
virtual ~FileLogPolicy()
{
}
private:
std::unique_ptr<std::ofstream> logFile; //Pointer to logging stream
static const char *const S_FILE_NAME; //File name used to store logging
size_t d_maxLogFileSize; //File max size used to store logging
};
Basically I create object of policy class and would like to log stuff, depending on the policy chosen. So for example I create logger like this:
FileLogPolicy log("log.txt");
In this case it should use Logger to save logs to file, by calling static_cast<LogPolicy*>(this)->write(buffer.str()). Apparently calling write function works fine but stream object is changing to null. How is that possible if FileLogPolicy destructor has not been called yet? When I change logFile to be normal pointer all works well. I don't get it where is the difference.
~Logger()
{
print_impl(END_OF_LOGGING);
}
this code runs after the descendend class has been destroyed.
void print_impl()
{
static_cast<LogPolicy*>(this)->write(buffer.str());
buffer.str("");
}
it then casts this to be a pointer to a class that this is no longer.
The unique ptr is gone, and even accessing the member is UB.
Related
I'm creating a console application and have the need for a menu.
This menu can link to a next menu or preform an action.
What is a good OOP way of doing this?
I've seen many do it like this, but isn't really maintainable
TJ::clearScreen(); // Function I wrote to clear the console
TJ::breakSection('='); // Creates a line of "===...==="
std::cout << "Main menu" << std::endl;
TJ::breakSection();
std::cout << "[1] abcd" << std::endl;
std::cout << "[2] hrhdd" << std::endl;
std::cout << "[3] aeshsrh" << std::endl;
TJ::breakSection('=');
std::cin >> choice;
switch(choice) {
case 1:
doThing1();
break;
case 2:
doThing1();
break;
case 3:
doThing1();
break;
}
Is there a way to make it look like this?
menu.addChoice(functionA);
menu.addChoice(menuB);
menu.addChoice(functionC);
menu.addChoice(menuD);
menu.display();
So if the user chooses option A (by typing "A" into the console), it will execute functionA. If the user chooses option B, it will show menuB.
I've looked at doing something like you see below. But I can't figure out how to allow both functions and menus to be chosen.
class Menu {
private:
std::string title;
class Item {
private:
public:
Item();
~Item();
int run();
int display();
};
std::vector<Item> Choices;
public:
Menu();
~Menu();
Menu& addChoice();
Menu& display();
};
It looks like you are looking for function pointers.
You can store them in a vector like so:
std::vector<void (*) ()> options{&functionA , &displayMenuB, &functionC, &displayMenuD};
options[0](); // Executes function A
options[1](); // Shows menu B
The only issue is that displayMenuB needs to be a function here, not a piece of raw data... ( I did not completely understand your problem, but if you just want to display menu B to the console it could be a function returning a void).
Of course you need to wrap all of that in a class and properly encapsulate it, but I hope you get the idea.
Note: Function pointers can only point to stateless function. If you want to store a functors ( basically an object with some data but which can be called like a function ), you should use std::function.
I've put some efforts and created a kind of menu infrastructure for your problem. It can store functions with the same parameter list. Also, my implementation uses std::map, so it is more convenient and faster than std::vector indexing.
Menu.h
#pragma once
#include <functional>
#include <string>
#include <map>
using std::function;
using std::string;
using std::map;
template <class ...Types>
class Menu
{
private:
template <class ...Types>
class Item
{
private:
function<void(Types...)> func;
string desc;
public:
Item() = default;
Item(function<void(Types...)> func, string desc) : func(func), desc(desc) {}
void setDescription(string desc) { this->desc = desc; }
string getDescription() { return desc; }
void run(Types ... params) { func(std::forward<Types>(params)...); }
};
private:
string text;
map<string, Item<Types...>> choices;
public:
void addChoice(string key, function<void(Types...)> func, string desc = "");
void setText(string txt) { text = txt; }
void setDescription(string key, string desc);
void run(string key, Types ... params);
void display();
};
Menu.cpp
#include "Menu.h"
#include <iostream>
using std::cout;
using std::endl;
template<class ...Types>
void Menu<Types...>::addChoice(string key, function<void(Types...)> func, string desc)
{
Item<Types...> item{ func, desc };
this->choices[key] = item;
}
template<class ...Types>
void Menu<Types...>::setDescription(string key, string desc)
{
this->choices[key].setDescription(desc);
}
template<class ...Types>
void Menu<Types...>::run(string key, Types ... params)
{
if (choices.find(key) != choices.end())
this->choices[key].run(std::forward<Types>(params)...);
}
template<class ...Types>
void Menu<Types...>::display()
{
cout << this->text << endl;
for (auto& c : this->choices)
cout << "\t" << c.first << ": " << c.second.getDescription() << endl;
cout << endl;
}
template class Menu<>;
Main.cpp
#include <iostream>
#include "Menu.h"
using std::cout;
using std::cin;
using std::endl;
void funcA();
void funcB();
void funcC();
int main()
{
Menu<> menu;
menu.setText("Choose:");
menu.addChoice("A", funcA, "A description");
menu.addChoice("B", funcB /*no description*/);
menu.addChoice("C", funcC /*no description*/);
menu.setDescription("C", "C description");
menu.display();
string s;
std::getline(cin, s);
menu.run(s);
return 0;
}
void funcA()
{
cout << "Function A" << endl;
}
void funcB()
{
cout << "Function B" << endl;
}
void funcC()
{
cout << "Function C" << endl;
}
Output:
Choose:
A: Function A
B:
C: Function C
A
Function A
Don't forget about putting template class Menu<*types*>; for any other signature.
#include "dataConsumer.h"
#include <iostream>
#include <Windows.h>
DataConsumer::DataConsumer(){}
DataConsumer::~DataConsumer(){}
void DataConsumer::Body()
{
std::cout << "DataConsumer Start" << std::endl;
while (1)
{
//I want to get providerData_ of DataProvide class in here
Sleep(1000);
}
}
#include "dataProvider.h"
#include <iostream>
#include <Windows.h>
DataProvider::DataProvider(){}
DataProvider::~DataProvider(){}
void DataProvider::Body()
{
std::cout << "DataProvider Start" << std::endl;
while (1)
{
//Update data in here
providerData_++;
Sleep(1000);
}
}
There are two classes.
And I want to get providerData_ of dataProvider class in dataConsumer class.
To resolve this situation, I thought the following is one solution.
I made singleton dataTransfer class like below.
But I am not sure whether this is a general solution in c++.
First of all, I want to know whether my solution is available.
To the next, If you know the better solution(or design pattern) to resolve my situation, please advise to me.
#ifndef DATATRANSFER_H
#define DATATRANSFER_H
class DataTransfer
{
public:
static DataTransfer* getInstance()
{
static DataTransfer instance;
return &instance;
}
void GetData(unsigned int *data)
{
if(data)
*data = data_;
}
void SetData(unsigned int *data)
{
if(data)
data_ = *data;
}
private:
DataTransfer(){}
~DataTransfer(){}
unsigned int data_;
};
#endif
#include "dataConsumer.h"
#include "dataTransfer.h"
#include
#include
DataConsumer::DataConsumer(){}
DataConsumer::~DataConsumer(){}
void DataConsumer::Body()
{
unsigned int data = 0;
std::cout << "DataConsumer Start" << std::endl;
while (1)
{
//I want to get providerData_ of DataProvide class in here
DataTransfer::getInstance()->GetData(&data);
std::cout << "DataConsumer data:" << data << std::endl;
Sleep(1000);
}
}
#include "dataProvider.h"
#include "dataTransfer.h"
#include
#include
DataProvider::DataProvider() : providerData_(0)
{
}
DataProvider::~DataProvider(){}
void DataProvider::Body()
{
std::cout << "DataProvider Start" << std::endl;
while (1)
{
//Update data in here
providerData_++;
DataTransfer::getInstance()->SetData(&providerData_);
Sleep(1000);
}
}
If both classes need to be able to get and set the providerData_, I would create a third Data class to own the providerData_.
Then I could give a pointer of the Data class to all the classes that needed access to that data.
There are 3 patterns called aggregation, composition and association in software architecture.
The pattern in which class Foo can use class Bar but does not "own" it and both classes remain independent is Association.
DataConsumer have a pointer to DataProvider :
// Association
class DataConsumer{
private:
DataProvider* provider;
public:
void setProvider(DataProvider* p) { provider = p; }
void Body();
int /* or whatever data type */ getData()
{
if(provider != nullptr)
{
return provider->getData();
}
else
{
// handle provider not being set
return ...;
}
}
};
DataProvider must be allocated / created outside of DataConsumer and is independent.
Read this answer and this answer for a better explanation on these pattern.
[It is not necessary to follow the links to understand the question].
I combined the implementation of the singleton pattern in this answer, together with the synchronized file writing of this other answer.
Then I wanted to see if the interface of SynchronizedFile could provide a variadic templated write method, but I couldn't figure out how to properly combine this with the std::lock_guard.
Below is a non-working example. In this case it doesn't work because (I think) the two threads manage to pump stuff into the buffer i_buf in a non-synchronized way, resulting in a garbled LOGFILE.txt.
If I put the std::lock_guard inside the general template of write then the program doesn't halt.
#include <iostream>
#include <mutex>
#include <sstream>
#include <fstream>
#include <string>
#include <memory>
#include <thread>
static const int N_LOOP_LENGTH{10};
// This class manages a log file and provides write method(s)
// that allow passing a variable number of parameters of different
// types to be written to the file in a line and separated by commas.
class SynchronizedFile {
public:
static SynchronizedFile& getInstance()
{
static SynchronizedFile instance;
return instance;
}
private:
std::ostringstream i_buf;
std::ofstream i_fout;
std::mutex _writerMutex;
SynchronizedFile () {
i_fout.open("LOGFILE.txt", std::ofstream::out);
}
public:
SynchronizedFile(SynchronizedFile const&) = delete;
void operator=(SynchronizedFile const&) = delete;
template<typename First, typename... Rest>
void write(First param1, Rest...param)
{
i_buf << param1 << ", ";
write(param...);
}
void write()
{
std::lock_guard<std::mutex> lock(_writerMutex);
i_fout << i_buf.str() << std::endl;
i_buf.str("");
i_buf.clear();
}
};
// This is just some class that is using the SynchronizedFile class
// to write stuff to the log file.
class Writer {
public:
Writer (SynchronizedFile& sf, const std::string& prefix)
: syncedFile(sf), prefix(prefix) {}
void someFunctionThatWritesToFile () {
syncedFile.write(prefix, "AAAAA", 4343, "BBBBB", 0.2345435, "GGGGGG");
}
private:
SynchronizedFile& syncedFile;
std::string prefix;
};
void thread_method()
{
SynchronizedFile &my_file1 = SynchronizedFile::getInstance();
Writer writer1(my_file1, "Writer 1:");
for (int i = 0; i < N_LOOP_LENGTH; ++ i)
writer1.someFunctionThatWritesToFile();
}
int main()
{
std::thread t(thread_method);
SynchronizedFile &my_file2 = SynchronizedFile::getInstance();
Writer writer2(my_file2, "Writer 2:");
for (int i = 0; i < N_LOOP_LENGTH; ++i)
writer2.someFunctionThatWritesToFile();
t.join();
std::cout << "Done" << std::endl;
return 0;
}
How could I successfully combine these three ideas?
The program deadlocks because write calls itself recursively while still holding the lock.
Either use a std::recursive_mutex or release the lock after writing your data out but before calling write.
E: Unlocking doesn't do the job, I didn't think this through...
E: Or lock once and defer to another private method to do the write.
template<typename... Args>
void write(Args&&... args)
{
std::unique_lock<std::mutex> lock(_writerMutex);
_write(std::forward<Args>(args)...);
}
template<typename First, typename... Rest>
void _write(First&& param1, Rest&&... param) // private method
{
i_buf << std::forward<First>(param1) << ", ";
_write(std::forward<Rest>(param)...);
}
void _write()
{
i_fout << i_buf.str() << std::endl;
i_buf.clear();
}
I have a strange issue where ostringstream is empty even though I insert an output to it.
Here is my code:
//logger.h
#include <string>
#include <iostream>
#include <sstream>
using std::string;
class BasicLogger {
public:
BasicLogger(const string name);
BasicLogger(const BasicLogger& basicLogger);
~BasicLogger();
template<class T>
BasicLogger& operator<<(const T &msg){
std::cout << "msg is: " << msg << std::endl;
mBuf << msg;
std::cout << "mBuf is: " << mBuf.str() << std::endl;
return *this;
}
private:
string mName;
std::ostringstream mBuf;
};
class Logger {
public:
Logger();
~Logger();
BasicLogger info();
BasicLogger error();
private:
BasicLogger mInfoLogger;
BasicLogger mErrorLogger;
};
//logger.cpp
#include "logger.h"
BasicLogger::BasicLogger(const string name):
mName(name) { }
BasicLogger::BasicLogger(const BasicLogger& otherLogger) {
this->mName = otherLogger.mName;
this->mBuf << otherLogger.mBuf.rdbuf();
}
BasicLogger::~BasicLogger() { }
Logger::Logger():
mInfoLogger("[INFO]"),
mErrorLogger("[ERROR]") {}
Logger::~Logger() {};
BasicLogger Logger::info() {
return mInfoLogger;
}
BasicLogger Logger::error() {
return mErrorLogger;
}
//main.cpp
#include "logger.h"
int main() {
Logger logger;
logger.info() << "Hellooo";
}
The output is
msg is: Hellooo
mBuf is:
While #BoPersson already gave you the solution, I would like to explain what happened here, and why your output is empty, even though you are adding to ostringstream on the line just before you display its content.
I think when you attempted to return mInfoLogger by value, the compiler complained about not being able to return it because copy constructor was deleted. The reason it was deleted because ostringstream member you have is non-copyable.
So you provided custom copy constructor and attempted to copy the stream this way:
this->mBuf << otherLogger.mBuf.rdbuf();
Only this does not copy anything as your rdbuf is empty and instead sets failbit on
The failbit
The streambuf overload of basic_ostream::operator<< if the function
inserts no characters.
http://en.cppreference.com/w/cpp/io/ios_base/iostate
If you were to check your message insertion like this:
if (!(mBuf << msg))
std::cout << "Not Inserted" << std::endl;
You would see Not Inserted message printed. There are many ways to make it print the desired message. For example making sure your rdbuf buffer is not empty or by resetting the failbit before you reuse the mBuf, something like mBuf.clear(); or simply by returning the reference to mInfoLogger (and mErrorLogger). Then you can safely get rid of your copy constructor.
I'm looking for 'best-practice' in the following situation:
In general, there are three common ways to share private data between two (or more) non-member functions with differential advantages and disadvantages:
// Example 1: using 'static' class
// HPP
namespace foo {
class bar
{
private:
static const char* const s_private;
bar();
public:
static void s_method0();
static void s_method1();
}; /* class bar */
} /* namespace foo */
// CPP
namespace foo {
const char* const bar::s_private = "why do I need to be visible in HPP?";
void bar::s_method0() { std::cout << "s_method0 said: " << s_private << std::endl; }
void bar::s_method1() { std::cout << "s_method1 said: " << s_private << std::endl; }
} /* namespace foo */
// Example 2: using unnamed-namespace
// HPP
namespace foo {
void bar0();
void bar1();
} /* namespace foo */
// CPP
namespace foo {
namespace {
const char* const g_anonymous = "why do I need external linkage?";
} /* unnamed-namespace */
void bar0() { std::cout << "bar0 said: " << g_anonymous << std::endl; }
void bar1() { std::cout << "bar1 said: " << g_anonymous << std::endl; }
} /* namespace foo */
// Example 3: using static keyword in namespace-scope
// HPP
namespace foo {
void bar0();
void bar1();
} /* namespace foo */
// CPP
namespace foo {
static const char* const g_internal = "nobody outside this file can see me and I don't have external linkage";
void bar0() { std::cout << "bar0 said: " << g_internal << std::endl; }
void bar1() { std::cout << "bar1 said: " << g_internal << std::endl; }
} /* namespace foo */
I prefer 'Example 3' because it's as close to the intention as it could be.
But now I'm running in some problem's using templated functions. 'Example 1' seems to be the only way to solve this:
// HPP
namespace foo {
class bar
{
private:
static const char* const s_private;
bar();
public:
template<typename T> static void s_method0() { std::cout << "s_method0 said: " << s_private << std::endl; }
template<typename T> static void s_method1() { std::cout << "s_method1 said: " << s_private << std::endl; }
}; /* class bar */
} /* namespace foo */
// CPP
namespace foo {
const char* const bar::s_private = "why do I need to be visible in HPP?";
} /* namespace foo */
That's unsatisfying. Especialy because there are other (in this case methods) non-member function which should be in the same (in this case class-) scope, which don't need to access this private data.
Does anybody know an elegant solution?
Thanks for any help.
Best regards.
This is, somewhat unfortunately, an issue that springs quite often with template.
But may I suggest that you are over-engineering here ?
The truth is, whether you look at Loki code (by Andrei Alexandrescu) or Boost code (infamous David Abrahams notably), no-one really bothered to provide a better privacy.
Rather, they simply relied on convention and used a Private namespace (Loki) or a detail namespace (Boost, with sometimes a longer and more descriptive name to prevent clashes).
It's annoying, but there is not much you can do in practice.... though I actually have a solution for your specific problem ;)
// Evil solution!
#ifdef MY_SUPER_MACRO
# error "MY_SUPER_MACRO is already defined!"
#endif
#define MY_SUPER_MACRO "Some string"
template <typename T> void foo() { std::cout << "foo - " MY_SUPER_MACRO "\n"; }
template <typename T> void bar() { std::cout << "bar - " MY_SUPER_MACRO "\n"; }
#undef MY_SUPER_MACRO
And hop, I achieved locality in a header with an evil macro :)
If I understand correctly, your complaint/concern is that unlike with templates, with non-templates, one can define the function bodies inside the CPP, rather than the header, in which case they can access non-class statics, which are "invisible" to the outside world, including member functions defined in the header. This is all true.
However, remember that there's nothing stopping one defining other member functions in the CPP as well, in which case, they'd be equally able to access the static data. So really, the situation is no different. Your complaint is based on a false dichotomy.
If you genuinely want to prevent anything but s_method0<T>() and s_method1<T>() accessing s_private, then you must put them all in a dedicated class. It's as simple as that. This would be the case even for non-templates.
I had played around with the different techniques. My idea, using the unnamed namespace in the header file, was to 'mark' the 'shared'-classes as 'header-file-only'. Sure, due to the fact they aren't containing public members you cannot make nasty things anyway with it. But I thought it would be more close to the intention.
But I was wrong! After thinking about this I'm in shame. It's so logically simple. This example is showing what's the problem with it (entire code for clearness):
// header0.hpp
#ifndef HPP_HEADER0_INCLUDED
#define HPP_HEADER0_INCLUDED
#include <iostream>
#include <string>
namespace ns {
template<typename T> void header0_func0();
template<typename T> void header0_func1();
namespace {
class header0
{
template<typename> friend void ns::header0_func0();
template<typename> friend void ns::header0_func1();
static std::string s_private;
}; /* class header0 */
} /* unnamed */
template<typename T> void header0_func0() { std::cout << "header0_func0: " << header0::s_private << std::endl; }
template<typename T> void header0_func1() { std::cout << "header0_func1: " << header0::s_private << std::endl; }
} /* namespace ns */
#endif /* HPP_HEADER0_INCLUDED */
// header1.hpp
#ifndef HPP_HEADER1_INCLUDED
#define HPP_HEADER1_INCLUDED
#include <iostream>
#include <string>
namespace ns {
template<typename T> void header1_func0();
template<typename T> void header1_func1();
namespace {
class header1
{
template<typename> friend void ns::header1_func0();
template<typename> friend void ns::header1_func1();
static std::string s_private;
}; /* class header1 */
} /* unnamed */
template<typename T> void header1_func0() { std::cout << "header1_func0: " << header1::s_private << std::endl; }
template<typename T> void header1_func1() { std::cout << "header1_func0: " << header1::s_private << std::endl; }
} /* namespace ns */
#endif /* HPP_HEADER1_INCLUDED */
// source.cpp
#include "header0.hpp"
#include "header1.hpp"
std::string ns::header0::s_private = "header0 private data definition by source.cpp",
ns::header1::s_private = "header1 private data definition by source.cpp";
namespace {
// hide private class
class source
{
source();
~source();
static source s_instance;
};
source::source() {
std::cout << "source.cpp:\n";
ns::header0_func0<int>();
ns::header0_func1<int>();
ns::header1_func0<int>();
ns::header1_func1<int>();
std::cout << '\n';
}
source::~source() { }
source source::s_instance;
} /* unnamed */
By now everything seems to be OK. But what happen's if we try to use our headers in other translation units? Let's take a look:
// main.cpp
#include "header0.hpp"
#include "header1.hpp"
int main()
{
std::cout << "main.cpp:\n";
ns::header0_func0<int>();
ns::header0_func1<int>();
ns::header1_func0<int>();
ns::header1_func1<int>();
std::cout << '\n';
return 0;
}
What happens is, that we are ending with 2 unresolved externals. So, is the linker just an idiot? No, he is not. Thinking about what are unnamed namespace used for, we know what's going on. An unnamed namespace has an unique identifier in each translation unit. Thus, in our main.cpp, the linker doesn't know the definition of our private data in source.cpp.
So, what happens if we define this private data in main.cpp - just to bring matters to a head - ?
// main.cpp
#include "header0.hpp"
#include "header1.hpp"
std::string ns::header0::s_private = "header0 private data definition by main.cpp",
ns::header1::s_private = "header1 private data definition by main.cpp";
int main()
{
std::cout << "main.cpp:\n";
ns::header0_func0<int>();
ns::header0_func1<int>();
ns::header1_func0<int>();
ns::header1_func1<int>();
std::cout << '\n';
return 0;
}
Now, everything is compiling and getting linked 'correctly' - or rather, it seems so.
This is the console output of that program:
source.cpp:
header0_func0: header0 private data definition by source.cpp
header0_func1: header0 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
main.cpp:
header0_func0: header0 private data definition by source.cpp
header0_func1: header0 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
header1_func0: header1 private data definition by source.cpp
That means: If undefined behavior is what you are looking for, here you are.
In other words: Based on the explanation above: Don't use unnamed namespace in header files to encapsulate private shared data.
And the last question is, "what's the solution?"
If you don't want to use 'static' (utility) classes, you should prefer my first posted solution (only changed code):
// header0.hpp
// ...
namespace ns {
// ...
namespace detail {
class header0 { /*...*/ };
} /* namespace detail */
template<typename T> void header0_func0() { std::cout << "header0_func0: " << detail::header0::s_private << std::endl; }
template<typename T> void header0_func1() { std::cout << "header0_func1: " << detail::header0::s_private << std::endl; }
} /* namespace ns */
// ...
// header1.hpp
// ...
namespace ns {
// ...
namespace detail {
class header1 { /*...*/ };
} /* namespace detail */
template<typename T> void header0_func0() { std::cout << "header0_func0: " << detail::header1::s_private << std::endl; }
template<typename T> void header0_func1() { std::cout << "header0_func1: " << detail::header1::s_private << std::endl; }
} /* namespace ns */
// ...
// source.cpp
// ...
std::string ns::detail::header0::s_private = "header0 private data definition by source.cpp",
ns::detail::header1::s_private = "header1 private data definition by source.cpp";
// ...
I'm looking forward to any comment. Best regards.
What about that?
namespace foo {
namespace detail {
class shared
{
template<typename> friend void bar0();
template<typename> friend void bar1();
static const char* const m_private;
}; /* class shared */
} /* namespace detail */
template<typename T> void bar0() { std::cout << "bar0 said: " << detail::shared::m_private << std::endl; }
template<typename T> void bar1() { std::cout << "bar1 said: " << detail::shared::m_private << std::endl; }
} /* namespace foo */
EDIT 2:
OBSOLETE ANSWER. THIS CODE ISN'T WORKING! POSTED AN EXPLANATION BELOW.
EDIT:
In 'real code' I would replace namespace detail by an unnamed namespace. This would bring up the possibility to add other shared resources in different header files using the same name-scope:
namespace foo {
template<typename T> void bar0();
template<typename T> void bar1();
template<typename T> void bar2();
template<typename T> void bar3();
namespace {
class shared0
{
template<typename> friend void foo::bar0();
template<typename> friend void foo::bar1();
static const char* const m_private0;
}; /* class shared0 */
class shared1
{
template<typename> friend void foo::bar2();
template<typename> friend void foo::bar3();
static const char* const m_private1;
}; /* class shared1 */
} /* unnamed */
template<typename T> void bar0() { std::cout << "bar0 said: " << shared0::m_private0 << std::endl; }
template<typename T> void bar1() { std::cout << "bar1 said: " << shared0::m_private0 << std::endl; }
template<typename T> void bar2() { std::cout << "bar0 said: " << shared1::m_private1 << std::endl; }
template<typename T> void bar3() { std::cout << "bar1 said: " << shared1::m_private1 << std::endl; }
} /* namespace foo */