C++11: any easier way of template class method inline declaration? - templates

This question builds up on my:
C++ library: .hpp + .inl (separate definitions and declarations) vs .hpp only (in-class body code)
Moving templated functions into inline files is definitely an official hell. See below three examples. From my OLD neat way of doing things (#0), to a really expanded way (#1), to a more compacted way (#2) to the imaginary dream pipe way (#3).
// #0 the actual class definition
namespace CA {
template <typename tnChar>
class MyClass {
public:
typedef tnChar tChar;
typedef std::basic_string<tChar> tString;
MyClass(); // {}
tString Method1(const tString& aParam) const; // { return aParam; }
};
};
This is the inline version #1. It has both namespace and class.
template <typename tnChar>
CA::MyClass<tnChar>::MyClass(){}
template <typename tnChar>
typename CA::MyClass<tnChar>::tString
CA::MyClass<tnChar>::Method1(const tString& aParam) const {
return aParam;
}
template <> // specializing
typename CA::MyClass<wchar_t>::tString
CA::MyClass<wchar_t>::Method1(const tString& aParam) const {
return aParam;
}
This is the inline version #2. It is wrapped in namespace. Saved from adding the CA::.
namespace CA {
template <typename tnChar>
MyClass<tnChar>::MyClass(){}
template <typename tnChar>
typename MyClass<tnChar>::tString
MyClass<tnChar>::Method1(const tString& aParam) const {
return aParam;
}
template <> // specializing
typename MyClass<wchar_t>::tString
MyClass<wchar_t>::Method1(const tString& aParam) const {
return aParam;
}
}
This is the inline version #3. It is wrapped in namespace and class. Saved from adding the template <...> ... CA::MyClass. IMAGINARY version. Not possible but desirable!
#if 0 // like this is ever gonna work
// inline version #3 (IMAGINARY)
// wrapped in namespace and in class
// 'inline class' should make this functionality happen in C++my
namespace CA {
template <typename tnChar>
inline class MyClass { // :)
MyClass(){}
tString Method1(const tString& aParam) const {
return aParam;
}
};
template <>
inline class MyClass<wchar_t> { // :) - too much imagination
tString Method1(const tString& aParam) const {
return aParam;
}
};
}
#endif // disabled
My question is: Is anything like version 3 even remotely possible? Without having to typename the return values and write the template <...> each and every single time. I know the reasons why we need to do this, but I'm wondering if the new C++11 or the next C++14 has any plans to address template class inline method grouping?
Having the inline class keywords trigger the imaginary functionality in #3 would be mind blowing and it would make externalizing template class methods so easy... and logic... and grouped... and short :)

At the risk of stating the obvious, that syntax is available when declaring member functions inside the class body. If your religion requires you to put the member functions in a separate .inl file, you could include that file inside the class body itself.

Related

Separate compilation model for libraries that use templates [duplicate]

Suppose that I have two template functions declared in a header file:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
And suppose that the implementation of these functions (also in a header file and not in a source file, because they are templates) uses some implementation helper function, which is also a template:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
In any source file that I include the header file, the helper function will be visible. I don't want that, because the helper function is just an implementation detail. Is there a way to hide the helper function?
A common approach (as used in many Boost libraries, for example) is to put the helper in a namespace called details, possibly in a separate header (included from the "public" header).
There's no way to prevent it from being visible, and callable, but this quite clearly indicates that it is part of the implementation, not the interface.
The established precedent is to put that sort of thing in a specially (i.e. consistently) named nested namespace. Boost uses namespace details, Loki uses namespace Private. Obviously nothing can prevent anyone from using the contents of those namespaces, but both names convey the meaning that their contents aren't intended for general consumption.
That being said, an easy alternative is to turn func1 and func2 from free function templates into static member function templates of some common class; this way, helper can simply be a private member of said class, invisible to the outside world:
struct funcs {
template<typename T>
static void func1(T const& value) {
// ...
helper(value);
}
template<typename T>
static void func2(T const& value) {
// ...
helper(value);
}
private:
template<typename T>
static void helper(T const& value) {
// ...
}
};
Two options off the top of my head:
Move all the implementation to an hpp file which you include at the bottom of your h file.
Refactor your code as class templates, then make the helpers private.
Since the user of your code needs to see the full definition of the func1 function, its implementation, nor its helper function implementation, cannot be hidden.
But if you move the implementation into another file, the user will only have to be confronted with the template declaration:
//templates.h
template< typename T > void f1( T& );
#include <templates_impl.h> // post-inclusion
And the definition:
// templates_impl.h
template< typename T > void f1_helper( T& ) {
}
template< typename T > void f1( T& ) {
// the function body
}
In C++20 you can now use modules.
For this you could create a module some_module.cppm holding all functions and marking only the interface (either the individual functions or a namespace) with export while not exposing the helper functions:
// some_module.cppm
export module some_module;
template <typename T>
void helper(const T& value) {
// ...
}
export
template <typename T>
void func1(const T& value) {
// ...
helper(value);
}
export
template <typename T>
void func2(const T& value) {
// ...
helper(value);
}
In the case above only the functions func1 and func2 are exported and can be accessed inside main.cpp:
// main.cpp
#include <cstdlib>
import some_module;
int main() {
func1(1.0);
func2(2.0);
return EXIT_SUCCESS;
}
In clang++12 you can compile this code with the following three commands:
clang++ -std=c++2b -fmodules-ts --precompile some_module.cppm -o some_module.pcm
clang++ -std=c++2b -fmodules-ts -c some_module.pcm -o some_module.o
clang++ -std=c++2b -fmodules-ts -fprebuilt-module-path=. some_module.o main.cpp -o main
./main
I would (as said before) make a template class, make all functions static and the helper function private. But besides that I'd also recommend making the constructor private as shown below:
template <typename T>
class Foo{
public:
static void func1(const T& value);
static void func2(const T& value);
private:
Foo();
static void helper(const T& value);
}
When you make the constructor private, the compiler won't allow instances of this template class. So the code below would become illegal:
#include "foo.h"
int main(){
int number = 0;
Foo<int>::func1(number); //allowed
Foo<int>::func2(number); //allowed
Foo<int>::helper(number); //not allowed, because it's private
Foo<int> foo_instance; //not allowed, because it's private
}
So why would someone want this? Because having different instances that are EXACTLY the same is something you probably never want. When the compiler tells you that the constructor of some class is private, then you can assume that having different instances of it would be unnecesarry.
I know you mean that you want to hide it so finely that callers have no way to find your helper functions as long as they don't change your code file. I know it so well because I have very similar needs recently.
So how about wrapping your helper functions in an anonymous namespace? This is recently the most elegant style I found:
namespace YourModule
{
namespace
{//Your helper functions}
//Your public functions
}
This practice effectively hides your internal functions from the outside. I can't find any way that a caller can access functions in anonymous namespaces.
It's usually not a good practice, as answered by #user3635700 , to convert your namespace to a class full of static functions, especially when you have templates of static variables like:
template <uint8_t TimerCode>
static uint16_t MillisecondsElapsed;
If this variable appears in a class, you'll have to initialize it somewhere outside the class! However, you can't do it because it's a template! WTF!
It seems that an anonymous namespace in the header file, which is criticized by some, is the only and the most perfect solution to our needs.

C++ - Separate declaration/definition for template function in template class

I am aware that the syntax for declaring a template class method in a header and defining it in a source file goes as so:
myclass.h
template <typename T>
class MyClass {
public:
void method(T input);
private:
T privVar;
};
myclass.cpp
template <typename T>
void MyClass<T>::method(T input) {
privVar = input;
}
But, what if the method is also a template?
I am adding methods to the basic_string class, and I want to know how to write the implementation for the functions.
MyString.h
template <class _Elem = TCHAR,
class _Traits = std::char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
class String
: public std::basic_string<_Elem, _Traits, _Ax> {
private:
// Types for the conversion operators.
typedef _Elem* _StrTy;
typedef const _Elem* _ConstStrTy;
//...
public:
// Conversion operators so 'String' can easily be
// assigned to a C-String without calling 'c_str()'.
operator _StrTy() const {
return const_cast<_StrTy>(this->c_str());
}
operator _ConstStrTy() const {
return this->c_str();
}
// ... Constructors ...
/*------------ Additional Methods ------------*/
//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val);
//! Converts a string to the given type.
template <class _ValTy> static _ValTy ConvertTo(const String& str);
template <class _ValTy> _ValTy ConvertTo(void) const;
//! Checks if a string is empty or is whitespace.
static bool IsNullOrSpace(const String& str);
bool IsNullOrSpace(void) const;
//! Converts a string to all upper-case.
static String ToUpper(String str);
void ToUpper(void);
// ...
};
How could I implement template <class _ValTy> static String ConvertFrom(_ValTy val);? Because now not only do I need to specify the class template, but the function template too. I am betting the code I'm about to write isn't valid, but it should show what I am trying to accomplish:
MyString.cpp
template <class _Elem, class _Traits, class _Ax>
template <class _ValTy>
String<_Elem, _Traits, _Ax> String<_Elem, _Traits, _Ax>::ConvertFrom(_ValTy val) {
// Convert value to String and return it...
}
I am not advanced at all with templates. Not only am I very doubtful that the above is valid, it seems cumbersome to write and not very readable. How would I go about implementing the template methods, and the static template methods which returns its own class type? Because I don't want to define them in the header.
Syntax of definition of template member functions outside of template is like this:
template <class T> struct A
{
template <class X> void f();
};
template<class T> template<class X> void A<T>::f()
{
}
So your code is correct.
Would like to note that defining template members in .cpp is not very useful. In this case you shall explicitly instantiate them with all types you need to use with this template. Or do not use them outside this .cpp which doesn't make sense.
Before I answer your question, let me first say: Don't do this. Extend std::string by using free-functions instead, much like the standard library implements many algorithms. Additionally I'd suggest doing it for ranges rather than strings only but that's more subjective.
Also note that std::string avoids implicit conversions to C-strings not to make your life harder, but to protect your code from a wide variety of obscure bugs that can be caused by unexpected implicit conversions. I would think very long and hard about implementing them. Just think about this: It takes you a few extra moments to type.c_str() once when you write the code, and for the rest of eternity anyone who reads your code will immediately know that it's being used as a C-style string and not as a std::string.
To answer your question, just put the code in the header:
//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val)
{
// Code here
}
Finally note that identifiers starting with underscore+capital letter (and many other things starting with _) are reserved for the compiler and thus all bets are off as to your program's functionality.
Your function definition is valid, and it can't be defined outside of the class declaration in a less verbose way. Since you want to put the function definition in a .cpp file you can't take advantage of combining the function definition with the more concise function declaration. By putting the function definition in a .cpp file you will also have to explicitly instantiate all needed specializations of your template class.
Below is an attempt to make an example code for Rost and Josh's answers:
template.hpp
#pragma once
template<class T>
class Add
{
public:
T Addition(T summand1, T summand2);
};
void AddUsing( int summand1, int summand2 );
template.cpp
#include "template.hpp"
#include <iostream>
template<class T>
T Add<T>::Addition(T summand1, T summand2)
{
return summand1 + summand2;
}
void AddUsing( int summand1, int summand2 )
{
std::cout << Add<int>().Addition( summand1, summand2 ) << std::endl;
}
main.cpp
#include "template.hpp"
int main()
{
AddUsing ( 2, 2 );
}

Compile-time error for non-instantiated template members instead of link-time error

I have template class ItemContainer that actually is facade for a whole family of containers with different capabilities like sorting, indexing, grouping etc.
Implementation details are hidden in cpp. file using pimpl idiom and explicit instantiation. Template is instantiated only with well-known limited set of implementation classes that define the actual behavior of container.
Main template implements common functions supported by all containers - IsEmpty(), GetCount(), Clear() etc.
Each specific container specializes some functions that are supported only by it, e.g. Sort() for sorted container, operator[Key&] for key indexed container etc.
The reason for such design is that class is replacement for several legacy hand-made bicycle containers written by some prehistorics in early 90th. Idea is to replace old rotting implemenation with modern STL&Boost containers keeping old interface untouched as much as possible.
The problem
Such design leads to unpleasant situation when user tries to call unsupported function from some specialization. It compiles OK, but produces error on linking stage (symbol not defined).
Not very user friendly behavior.
Example:
SortedItemContainer sc;
sc.IsEmpty(); // OK
sc.Sort(); // OK
IndexedItemContainer ic;
ic.IsEmpty(); // OK
ic.Sort(); // Compiles OK, but linking fails
Of course, it could be completely avoided by using inheritance instead of specialization but I don't like to produce a lot of classes with 1-3 functions. Would like to keep original design.
Is there possibility to turn it into compile stage error instead of link stage one? I have a feeling that static assert could be used somehow.
Target compiler for this code is VS2008, so practical solution must be C++03 compatible and could use MS specific features.
But portable C++11 solutions also are welcome.
Source Code:
// ItemContainer.h
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class Impl> class ItemContainer
{
public:
// Common functions supported by all specializations
void Clear();
bool IsEmpty() const;
...
// Functions supported by sequenced specializations only
ItemPtr operator[](size_t i_index) const;
...
// Functions supported by indexed specializations only
ItemPtr operator[](const PrimaryKey& i_key) const;
...
// Functions supported by sorted specializations only
void Sort();
...
private:
boost::scoped_ptr<Impl> m_data; ///< Internal container implementation
}; // class ItemContainer
// Forward declarations for pimpl classes, they are defined in ItemContainer.cpp
struct SequencedImpl;
struct IndexedImpl;
struct SortedImpl;
// Typedefs for specializations that are explicitly instantiated
typedef ItemContainer<SequencedImpl> SequencedItemContainer;
typedef ItemContainer<IndexedImpl> IndexedItemContainer;
typedef ItemContainer<SortedImpl> SortedItemContainer;
// ItemContainer.cpp
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation classes definition, skipped as non-relevant
struct SequencedImpl { ... };
struct IndexedImpl { ... };
struct SortedImpl { ... };
// Explicit instantiation of members of SequencedItemContainer
template void SequencedItemContainer::Clear(); // Common
template bool SequencedItemContainer::IsEmpty() const; // Common
template ItemPtr SequencedItemContainer::operator[](size_t i_index) const; // Specific
// Explicit instantiation of members of IndexedItemContainer
template void IndexedItemContainer::Clear(); // Common
template bool IndexedItemContainer::IsEmpty() const; // Common
template ItemPtr IndexedItemContainer::operator[](const PrimaryKey& i_key) const; // Specific
// Explicit instantiation of members of SortedItemContainer
template void SortedItemContainer::Clear(); // Common
template bool SortedItemContainer::IsEmpty() const; // Common
template void SortedItemContainer::Sort(); // Specific
// Common functions are implemented as main template members
template <class Impl> bool ItemContainer<Impl>::IsEmpty() const
{
return m_data->empty(); // Just sample
}
// Specialized functions are implemented as specialized members (partial specialization)
template <> void SortedItemContaner::Sort()
{
std::sort(m_data.begin(), m_data.end(), SortFunctor()); // Just sample
}
...
// etc
If it is known at compile time that a certain function will not be implemented, then that function shouldn't have been declared in the first place. Otherwise, this is a programming error.
Having said that, you must avoid declaring such a function, or declare it such that the declaration only works if it will be implemented. That can be achieved either by a static_assert or by SFINAE.
For example
template<class Container> // you need one instantination per container supported
struct container_traits
{
static const bool has_sort; // define appropriately in instantinations
/* etc */
};
template<class container>
class ContainerWrapper {
unique_ptr<container> _m_container;
template<bool sorting> typename std::enable_if< sorting>::type
_m_sort()
{
_m_container->sort();
}
template<bool sorting> typename std::enable_if<!sorting>::type
_m_sort()
{
static_assert(0,"sort not supported");
}
public
void sort()
{
_m_sort<container_traits<container>::has_sort>();
}
/* etc */
};
Consider this example:
class A {
public:
void foo() {}
void bar();
};
Only during linking phase it could be detected an error that A::bar() is not defined and this has nothing to do with templates.
You shall define separate interfaces for your different containers and use them for your implementations. Just one of the possibilities below:
template <class Impl>
class ItemContainerImpl
{
public:
ItemContainerImpl();
protected:
boost::scoped_ptr<Impl> m_data; ///< Internal container implementation
};
// No operations
template <class Impl>
class Empty : protected virtual ItemContainerImpl<Impl> {};
template <class Impl, template <class> class Access, template <class> class Extra = Empty>
class ItemContainer : public Extra<Impl>, public Access<Impl>
{
public:
// Common functions supported by all specializations
void Clear();
bool IsEmpty() const;
...
};
template <class Impl>
class SequencedSpecialization : protected virtual ItemContainerImpl<Impl> {
public:
// Functions supported by sequenced specializations only
ItemPtr operator[](size_t i_index) const;
...
};
template <class Impl>
class IndexedSpecialization : protected virtual ItemContainerImpl<Impl> {
public:
// Functions supported by indexed specializations only
ItemPtr operator[](const PrimaryKey& i_key) const;
...
};
template <class Impl>
class Sorted : protected virtual ItemContainerImpl<Impl> {
public:
// Functions supported by sorted specializations only
void Sort();
...
};
// Typedefs for specializations that are explicitly instantiated
typedef ItemContainer<SequencedImpl, SequencedSpecialization> SequencedItemContainer;
typedef ItemContainer<IndexedImpl, IndexedSpecialization> IndexedItemContainer;
typedef ItemContainer<SortedImpl, IndexedSpecialization, Sorted> SortedItemContainer;
Despite the good answers suggesting to use SFINAE, I continued to search solution that will meet my original design. And finally I found it.
The key idea is to use specialization for specific function members instead of explicit instantiation.
What was done:
Added specific functions dummy implementation for main template. Implementations containing static asserts only were placed in header file but not inlined into class definition.
Specific functions explicit instantiations were removed from .cpp file.
Specific functions specialization declarations were added to header file.
Source Code:
// ItemContainer.h
//////////////////////////////////////////////////////////////////////////////
template <class Impl> class ItemContainer
{
public:
// Common functions supported by all specializations
void Clear();
bool IsEmpty() const;
...
// Functions supported by sorted specializations only
void Sort();
...
private:
boost::scoped_ptr<Impl> m_data; ///< Internal container implementation
}; // class ItemContainer
// Dummy implementation of specialized function for main template
template <class Impl> void ItemContainer<Impl>::Sort()
{
// This function is unsupported in calling specialization
BOOST_STATIC_ASSERT(false);
}
// Forward declarations for pimpl classes,
// they are defined in ItemContainer.cpp
struct SortedImpl;
// Typedefs for specializations that are explicitly instantiated
typedef ItemContainer<SortedImpl> SortedItemContainer;
// Forward declaration of specialized function member
template<> void CSortedOrderContainer::Sort();
// ItemContainer.cpp
//////////////////////////////////////////////////////////////////////////////
// Implementation classes definition, skipped as non-relevant
struct SortedImpl { ... };
// Explicit instantiation of common members of SortedItemContainer
template void SortedItemContainer::Clear();
template bool SortedItemContainer::IsEmpty() const;
// Common functions are implemented as main template members
template <class Impl> bool ItemContainer<Impl>::IsEmpty() const
{
return m_data->empty(); // Just sample
}
// Specialized functions are implemented as specialized members
// (partial specialization)
template <> void SortedItemContaner::Sort()
{
std::sort(m_data.begin(), m_data.end(), SortFunctor()); // Just sample
}
...
// etc
This way it works at least for VS2008.
For GCC with C++11 static_assert usage requires some trick to enable lazy template function instatiation (compiled sample):
template <class T> struct X
{
void f();
};
template<class T> void X<T>::f()
{
// Could not just use static_assert(false) - it will not compile.
// sizeof(T) == 0 is calculated only on template instantiation and
// doesn't produce immediate compilation error
static_assert(sizeof(T) == 0, "Not implemented");
}
template<> void X<int>::f()
{
std::cout << "X<int>::f() called" << std::endl;
}
int main()
{
X<int> a;
a.f(); // Compiles OK
X<double> b;
b.f(); // Compilation error - Not implemented!
}
What about this ?
template <class T, class supported_types> struct vec_enabler :
boost::mpl::contains<supported_types, T> {};
// adding Sort interface
template <class T, class enabler, class Enable = void>
struct sort_cap{};
template <class T, class enabler>
struct sort_cap<T, enabler,
typename boost::enable_if< typename enabler::type >::type>
{
void Sort();
};
// adding operator[]
template <class T, class U, class R, class enabler, class Enable = void>
struct index_cap{};
template <class T, class primary_key, class ret, class enabler>
struct index_cap<T, primary_key, ret, enabler,
typename boost::enable_if< typename enabler::type >::type>
{
ret operator[](primary_key i_index) const;
};
template <class Impl>
class ItemContainer :
public sort_cap<Impl,
vec_enabler<Impl, boost::mpl::vector<A, B> > >, // sort for classes A or B
public index_cap<Impl, size_t, ItemPtr,
vec_enabler<Impl, boost::mpl::vector<C> > >, // index for class C
public index_cap<Impl, primaryKey, ItemPtr,
vec_enabler<Impl, boost::mpl::vector<B> > > // index for class B
{
public:
void Clear();
bool IsEmpty() const;
};
I find that using inheritance is the most clean way to achieve what you would like to do (which is 'adding interfaces to a class'.) Then we have the following:
int main(){
ItemContainer<A> cA;
cA.Sort();
//ItemPtr p = cA[0]; // compile time error
ItemContainer<C> cC;
//cC.Sort(); // compile time error
ItemPtr p = cC[0];
//ItemPtr pp= cC[primaryKey()]; // compile time error
}
Of course, you still are able to write the implementation in .cpp files.

Cannot successfully friend a templated method in a templated class because of mutual header inclusion

I have a class that wraps logic for matrix management. Meanwhile I have a set of methods specialized in handling some important time spending matrix manipulation operations (like LU factorization and so on).
The class uses the functions defined in that file. That file needs to have access to that class' elements. I need to make those specialized methods friends of the above-mentioned class. This causes me to include one header in each other header.
My problem
The situation I described before is coded here as follows. The first code refers to mat.hpp.
#ifndef MAT_HPP
#define MAT_HPP
#include "operations.hpp"
namespace nsA {
template <typename T>
// Templated class because matrices can be real or complex
class mat {
// Members...
friend template <typename U>
void exec_lu(const mat<U>& in, const mat<U>& out);
// Members...
} /* class end */
}
#endif
#endif
The second file is operations.hpp
#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA {
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
}
#endif
The problem is that the compiler starts complaining.
Note
Consider please that if I comment the friend declaration in mat.hpp but leave the inclusions, the compiler tells me that in 'operations.hpp' type mat is not defined!
If also comment the inclusion in mat.hpp and keep friend declaration commented as well, the compiler is ok!
How to work on this?
Thankyou
You can do this by just adding a couple of forward declarations... But you can even do better with a bit more code:
template <typename T> class mat;
template <typename T> void exec_lu( const mat<T>&, const mat<T>& );
template <typename T>
class mat {
friend void exec_lu<T>( const mat<T>&, const mat<T>& );
};
template <typename T>
void exec_lu( const mat<T>& a, const mat<T>& b ) { ... }
The main difference between this approach and yours (other than fixing the syntax limitations) is that in this approach a single instantiation of exec_lu is granted access to mat<T>, in particular the instantiation that needs access to it. In your code (after fixing), all specializations of exec_lu would have access to any specialization of mat (i.e. exec_lu<int> could access mat<int> private members, but also mat<double>...) and you probably don't want that.
For a longer description of the different options to declare friends of a template, read this answer to a related question.
To get this to work, you need to forward declare the class. It looks like this:
The file mat.hpp:
#ifndef MAT_HPP
#define MAT_HPP
namespace nsA {
template <typename T>
class mat;
namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}
template <typename T>
class mat {
friend void exec_lu(const mat<T>& in, const mat<T>& out);
};
}
#endif
And the file operations.hpp:
#ifndef OPERATIONS_HPP
#define OPERATIONS_HPP
#include "mat.hpp"
namespace nsA { namespace nsB {
template <typename T>
void exec_lu(const mat<T>& in, const mat<T>& out);
}}
#endif
Your original declaration gives out more friendship than mine. Mine only grants friendship to the function that matches the typename of the class.

How to hide an implementation helper template?

Suppose that I have two template functions declared in a header file:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
And suppose that the implementation of these functions (also in a header file and not in a source file, because they are templates) uses some implementation helper function, which is also a template:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
In any source file that I include the header file, the helper function will be visible. I don't want that, because the helper function is just an implementation detail. Is there a way to hide the helper function?
A common approach (as used in many Boost libraries, for example) is to put the helper in a namespace called details, possibly in a separate header (included from the "public" header).
There's no way to prevent it from being visible, and callable, but this quite clearly indicates that it is part of the implementation, not the interface.
The established precedent is to put that sort of thing in a specially (i.e. consistently) named nested namespace. Boost uses namespace details, Loki uses namespace Private. Obviously nothing can prevent anyone from using the contents of those namespaces, but both names convey the meaning that their contents aren't intended for general consumption.
That being said, an easy alternative is to turn func1 and func2 from free function templates into static member function templates of some common class; this way, helper can simply be a private member of said class, invisible to the outside world:
struct funcs {
template<typename T>
static void func1(T const& value) {
// ...
helper(value);
}
template<typename T>
static void func2(T const& value) {
// ...
helper(value);
}
private:
template<typename T>
static void helper(T const& value) {
// ...
}
};
Two options off the top of my head:
Move all the implementation to an hpp file which you include at the bottom of your h file.
Refactor your code as class templates, then make the helpers private.
Since the user of your code needs to see the full definition of the func1 function, its implementation, nor its helper function implementation, cannot be hidden.
But if you move the implementation into another file, the user will only have to be confronted with the template declaration:
//templates.h
template< typename T > void f1( T& );
#include <templates_impl.h> // post-inclusion
And the definition:
// templates_impl.h
template< typename T > void f1_helper( T& ) {
}
template< typename T > void f1( T& ) {
// the function body
}
In C++20 you can now use modules.
For this you could create a module some_module.cppm holding all functions and marking only the interface (either the individual functions or a namespace) with export while not exposing the helper functions:
// some_module.cppm
export module some_module;
template <typename T>
void helper(const T& value) {
// ...
}
export
template <typename T>
void func1(const T& value) {
// ...
helper(value);
}
export
template <typename T>
void func2(const T& value) {
// ...
helper(value);
}
In the case above only the functions func1 and func2 are exported and can be accessed inside main.cpp:
// main.cpp
#include <cstdlib>
import some_module;
int main() {
func1(1.0);
func2(2.0);
return EXIT_SUCCESS;
}
In clang++12 you can compile this code with the following three commands:
clang++ -std=c++2b -fmodules-ts --precompile some_module.cppm -o some_module.pcm
clang++ -std=c++2b -fmodules-ts -c some_module.pcm -o some_module.o
clang++ -std=c++2b -fmodules-ts -fprebuilt-module-path=. some_module.o main.cpp -o main
./main
I would (as said before) make a template class, make all functions static and the helper function private. But besides that I'd also recommend making the constructor private as shown below:
template <typename T>
class Foo{
public:
static void func1(const T& value);
static void func2(const T& value);
private:
Foo();
static void helper(const T& value);
}
When you make the constructor private, the compiler won't allow instances of this template class. So the code below would become illegal:
#include "foo.h"
int main(){
int number = 0;
Foo<int>::func1(number); //allowed
Foo<int>::func2(number); //allowed
Foo<int>::helper(number); //not allowed, because it's private
Foo<int> foo_instance; //not allowed, because it's private
}
So why would someone want this? Because having different instances that are EXACTLY the same is something you probably never want. When the compiler tells you that the constructor of some class is private, then you can assume that having different instances of it would be unnecesarry.
I know you mean that you want to hide it so finely that callers have no way to find your helper functions as long as they don't change your code file. I know it so well because I have very similar needs recently.
So how about wrapping your helper functions in an anonymous namespace? This is recently the most elegant style I found:
namespace YourModule
{
namespace
{//Your helper functions}
//Your public functions
}
This practice effectively hides your internal functions from the outside. I can't find any way that a caller can access functions in anonymous namespaces.
It's usually not a good practice, as answered by #user3635700 , to convert your namespace to a class full of static functions, especially when you have templates of static variables like:
template <uint8_t TimerCode>
static uint16_t MillisecondsElapsed;
If this variable appears in a class, you'll have to initialize it somewhere outside the class! However, you can't do it because it's a template! WTF!
It seems that an anonymous namespace in the header file, which is criticized by some, is the only and the most perfect solution to our needs.