Suppose there is a global variable in a translation unit. It is constant, but not compile time constant (it is initialized with an object that has a non constexpr constructor). It is declared static since it should be private to the translation unit. Obviously, that global is defined in the .cpp file. However, now I have added a method template to that file that needs the global variable. Since it is a method that will be used by other translation units, it has to be put into the header. However, once it is in the header it can no longer access the global variable. What is the best practice to solve this problem?
There is, but a little tricky way to achieve your goals:
The variable is private, available only to some elements.
Your function template can access it.
Use private static variable in a class defined in header, and make your function/class templates friend of this class.
YourFile.h
class PrivateYourFileEntities {
private:
static const int SomeVariable;
// ... other variables and functions
template <class T>
friend class A;
template <class T>
friend void func();
// the rest of friends follows
};
template <class T>
void A<T>::func() {
int a = PrivateYourFileEntities::SomeVariable;
}
template <class T>
void func() {
int a = PrivateYourFileEntities::SomeVariable;
}
YourFile.cpp
const int PrivateYourFileEntities::SomeVariable = 7;
Put the method declaration into .h file and method body into .cpp file like:
.h file:
#include <iostream>
void myfunc1();
void myfunc2();
.cpp file:
#include "myheader.h"
static int myglobalvar=90;
void myfunc1()
{
cout << myglobalvar << endl;
}
void myfunc2()
{
cout << "Oh yeah" << endl;
}
Related
I try to use template to achieve this, but it doesn't work.
I define an Incomplete template class in the internal header file test_inner.hpp:
#define VISIBLE __attribute__((visibility("default")))
typedef int Dummy;
template <typename T> class Incomplete
{
};
And in the src file, I specialized the Incomplete<Dummy>:
#include "test_inner.hpp"
template <> class VISIBLE Incomplete<Dummy>
{
private:
int a = 3;
public:
int f()
{
std::cout << "a: " << a << std::endl;
return 0;
}
};
template class Incomplete<Dummy>;
extern "C" VISIBLE
void test(Incomplete<Dummy> *a)
{
a->f();
}
In the external header file, just declare the explicit instance of Incomplete:
#include "test_inner.hpp"
extern template class VISIBLE Incomplete<Dummy>;
extern "C" VISIBLE void test(Incomplete<Dummy> *a);
The above code will be built into a shared library, and the following is my test code:
#include "test.hpp"
test(new Incomplete<Dummy>);
The code is not working correctly, possibly due to it instantiates a totally different instance compared with the instance in the shared library.
In my case, I don't want to expose anything of the implementation, but the user is still able to inherit from the class and register the derived class to the library.
new requires complete type.
So you might create factory, and free function using your opaque type, something along:
// Header:
class MyHandle;
std::shared_ptr<MyHandle> CreateMyHandle(/*..*/);
void doJob(MyHandle&);
and cpp file contains definitions of the above.
Usage would be similar to
auto handle = CreateMyHandle();
doJob(*handle);
NOTE: this post is different from this one: Declare non-template friend function for template class outside the class, so please read my question before marking it as duplicate.
I want to declare a non-template friend function inside a class template, and the arguments and return type of that friend function is unrelated to the template argument. How should I do that?
Please note it is different from that previous question because in that question, arguments and return type of that friend function is related to the template argument.
Example, adapted from that question above:
// class.h
#include <iostream>
using namespace std;
template <typename T>
struct B
{
T value;
int value2;
B() : value2(1) {}
friend void modify(const int&); // unrelated to T!
void printValue2() {
modify(value2);
cout << value2 << endl;
}
};
// define friend function foo() in a class.cpp file, not in the header
void modify(const int &v) { v = v * 2 + 1; } // HOW should I write it?
// main.cpp
int main() {
B<int> b;
b.printValue2();
return 0;
}
I know I can declare modify() outside this template class so it becomes a vanilla, ordinary function. But I want only this template class to have access to modify(). Alternatively, to achieve this goal of access control, I could define modify() to be a static method in this template class, but that would make the method a template method, forcing me to define it in the header.
Followup: if the friend approach above doesn't work, how should I achieve the two goals at the same time:
access control: only that class template can access modify()
be able to define modify() in a *.cpp file, rather in a header.
Accepted Answer:
To achieve the two goals above, don't abuse friendship.
The best practice is let the class template privately inherit a non-template base class, and in that base class declare common non-template methods that are unrelated to template arguments.
Therefore, you are able to define these methods in a separate *.cpp file, reducing the header's size.
You might use private inheritance instead of friendship:
// class.h
#include <iostream>
class B_helper
{
protected:
static void modify(int &v);
};
template <typename T>
struct B : private B_helper
{
T value;
int value2;
B() : value2(1) {}
void printValue2() {
modify(value2);
std::cout << value2 << std::endl;
}
};
// class.cpp
void B_helper::modify(int &v) { v = v * 2 + 1; }
You do it like this:
// class.cpp
void modify(const int &v) { v = v * 2 + 1; }
You are effectively abusing friendship, but ok. What this means is that you need to work around what it means to declare a function with friend: It is only visible through ADL! Now there is no way to refer to modify, because modify doesn't depend on B, so B's scope is never searched for a function named modify.
There is a work-around, but it's not pretty. You need to declare modify in every function where you use it. You could also declare it in global scope, but then everyone can call it. Alternatively, you can always declare it in a detail namespace (but this has the same issue a bit):
template<typename T>
void B<T>::printValue2() {
void modify(const int&);
modify(value2);
cout << value2 << endl;
}
As I said in the comments, friendship controls access to a class. As long as your function modify() is a standalone function, it cannot be befriended. As you want to call it from a template, it cannot be hidden it in a .cpp file either, but must be visible with the definition of the class template B and its member using modify().
One solution is to put modify as a static method in a auxiliary non-template class, which in turn befriends the template B<>.
// file foo.h (header)
namespace foo {
template<typename> class B; // forward declaration
class exclusive_for_B
{
template<typename T>
friend class B<T>;
static void modify(int&x) // must take int&, not const int&
{ x &= x+42; }
};
template<typename T>
class B
{
int val;
public:
...
void printvalue()
{
exclusive_for_B::modify(val); // access via friendship
std::cout << val << '\n';
}
};
}
I have a number of templatic and inline functions defined in an header file (let's call it head.h). Currently, these functions use some global variables declared with extern in the same header and defined somewhere in one .cpp.
Everything works fine, but I would limit global variables scope only to the header where they are defined.
In other words every other .h or .cpp that includes my head.h wouldn't be able to see such globals.
Any way to achieve this result?
including header files just copies the content of the header file into the including cpp/h file. That means, you cannot really distinguish whether you do something in your header file or in a cpp/h file that includes your header file.
So, variables that are defined in a header file cannot be excluded. If they are in a cpp file and you would like to forbid extern, you could use an anonymous namespace:
namespace
{
int variable;
}
Best practice, obviously, would be to not use global variables at all. It is considered bad style for several reasons like readability, hard to determine dependencies, difficulties with testing, a really bad chance of extending your software and so on. So, you might reconsider this kind of architecture for your next project if refactoring is not an option here.
One way would be to put a class around it instead of a namespace, making all functions public static methods of that class and the global variables private static variables.
i.e.:
head.h:
class A
{
public:
template <typename T> static void MethodA(T const &value)
{
//...
}
inline static void MethodB(int a, int b)
{
// ...
}
private:
static int x;
static std::string y;
};
head.cpp:
int A::x = 0;
std::string A::y;
EDIT:
Another alternate method would be to define the globals as private static variables in a class and make all functions that are allowed to use them friend functions:
head.h:
template <typename T> void FunctionA(T const &value);
void FunctionB(int a, int b);
class Vars
{
friend template <typename T> void FunctionA(T const &value);
friend FunctionB(int a, int b);
private:
static int x;
static std::string y;
};
template <typename T> void FunctionA(T const &value)
{
// ...
// ... A::x ...
// ...
}
inline void FunctionB(int a, int b)
{
// ...
// ... A::y ...
// ...
}
head.cpp:
int A::x = 0;
std::string A::y;
No, it is not possible.
If you declare some variable as extern in a header1.h - this variable will be available in any other headers which include header1.h.
So I have a class:
class MyClass
public:
printSomeStuff() { //Including implementation here to save space
print(data);
}
private:
int data;
And a main program, with a template function defined outside:
template<typename T>
void print(T val) {
cout << val;
}
int main() {
MyClass a;
a.printSomeStuff();
}
The idea is that I could move MyClass somewhere else and be fine, but a new print function would need to be defined based on the scenario. Typically this would just be a cout.
If I try to actually use this style of coding, though, I get an error because print is not defined in MyClass.cpp.
How should I address this issue?
You should move your print() function into a header (and a suitable namespace) and include it into the translation units where it is needed, e.g.:
// print.h
#ifndef INCLUDED_PRINT
#define INCLUDED_PRINT
#include <iostream>
namespace utilities {
template <typename T>
void print(T const& val) {
std::cout << val;
}
}
#endif
You'd then include this header into the translation where it is used, e.g.
// MyClass.h
#ifndef INCLUDED_MYCLASS
#define INCLUDED_MYCLASS
#include "print.h"
class MyClass
public:
printSomeStuff() { //Including implementation here to save space
utilities::print(data);
}
private:
int data;
};
#endif
Put your template definition in its own header file and include it in your class implementation file.
That said, with something as trivial as printing, it may be must as easy to do it in the printSomeStuff method entirely. The extra indirection isn't really buying you anything.
The header in which print template is defined has to be accessible from the header in which MyClass is defined, but not necessarily from main, so you could move it to a separated header and include it from MyClass.hpp or even MyClass.cc
suppose I have a file alpha.h:
class Alpha {
public:
template<typename T> void foo();
};
template<> void Alpha::foo<int>() {}
template<> void Alpha::foo<float>() {}
If I include alpha.h in more than one cpp file and compile with GCC 4.4, it complains there are multiple definitions of foo<int> and foo<float> across multiple object files. Makes sense to me, so I change the last two lines to:
template<> extern void Alpha::foo<int>() {}
template<> extern void Alpha::foo<float>() {}
But then GCC says:
explicit template specialization
cannot have a storage class
ok... so how am I supposed to do this correctly? I'm worried that C++ doesn't allow what I'm trying to do in the first place, in which case is there a good idiom that will accomplish the same thing?
use inline keyword
template<> inline void Alpha::foo<int>() {}
alternatively, provide implementation in separate cpp file
You can forward declare as well as the inline option:
// .h
template<> void Alpha::foo<int>();
//.cpp
template<> void Alpha::foo<int>() {}
From the ODR point of view, a fully (explicitly) specialized template is no longer a template, so it is subject to the same ODR principles as a non-template entity of the same kind. (There are some exceptions from that rule, I believe, but it is good enough for our purposes).
In your case, for ODR purposes a fully specialized function template is an ordinary function. So, as an ordinary function it should be declared in the header file and defined in one and only one implementation file.
No separate declaration or inline keywork is required. PF below working code.
#include<iostream>
class temp
{
public:
template <class T>
T add1(T a, T b)
{
return (a + b);
}
};
template<>
std::string temp::add1<std::string>(std::string aa, std::string bb)
{
return aa+bb;
}
int main()
{
temp *tc = new temp();
std::cout << tc->add1<float>(5.7, 4.5) << std::endl;
std::cout << tc->add1<std::string>("my ","program") << std::endl;
}
output is :
10.2
my program