I am thinking of creating template class wrapper that is supposed to inherit all of template parameter functionality and add something on top of it. For structs and classes this would be pretty simple
class foo{ void bar(){} };
template<class T>
class baz : public T { void zab(){} };
int main(){
baz<foo> a;
}
Now, my question is if there is any way to be able to keep operators for built-in integral types without tons of manual specializing template for those types to be able to do it like this:
int main(){
baz<int> a;
int b = a + 2;
}
Can it be done? If so, how? (I know it will be necessary to do it with some magic specialization. I am just asking if it is possible to do it with one partial specialization)
With SFINAE friend class, you may reduce the specializations with template:
template <class T, typename Enabler = void>
class baz : public T { void zab(){} };
// specialization for integral type
template <class T>
class baz<T, std::enable_if_t<std::is_integral<T>::value>>
{
friend auto operator + (T lhs, T rhs) { /*..*/}
operator T() const { return value; }
// ...
T value;
};
Related
How can I define different struct members for different template parameters? I've tried to use the requires keyword the following way:
template<typename T> requires std::is_void_v<T>
class Foo
{
public:
void Bar()
{
}
};
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
But this does not compile:
Foo<T> Foo(void): could not deduce template argument for T
Foo<T> Foo(Foo<T>): expects 1 argument - 0 provided
Foo: requires clause is incompatabile with the declaration
Is this behaviour even possible in C++ 20?
While requires may be useful in general, its advantages for exactly matching one template parameter type are outweighed by the negatives.
Template specialization of types has been possible since C++03, maybe even C++98:
template<typename T>
class Foo;
template<>
class Foo<void>
{
public:
void Bar()
{
}
};
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
In order to use concepts, you should still follow the same overall pattern:
Declare the template
Define the primary and all specialized bodies for the template
Example assuming my_is_magic_v is a fancier concept, not just a single particular type.
template<typename T>
class Foo;
template<typename T> requires my_is_magic_v<T>
class Foo<T>
{
public:
void Bar()
{
}
};
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
Regarding the third error:
You cannot declare two primary class templates with the same name in the same scope. You can only declare one primary template and then add partial or explicit specializations for it. Partial specializations need to be more specialized than the primary template.
The syntax for a partial specialization is slightly different than what you are using (the syntax for primary templates) and a declaration of the primary template must precede the partial specialization:
// primary class template
template<typename T>
class Foo
{
public:
T* Bar()
{
if (!m_T)
m_T = new T();
return m_T;
}
private:
T* m_T{};
};
// partial specialization with (more) constraints
template<typename T> requires std::is_void_v<T>
class Foo<T> // <- Additional template argument list for partial specialization
{
public:
void Bar()
{
}
};
The other error messages are either a consequence of this issue as well or caused by a problem with how the template is used somewhere else that you are not showing.
I am currently struggling with templates: I have a templated class A, which performs basic math (for floats, doubles, complex numbers) and looks like this
template <typename T>
class A
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Now I can use the class like A<double>, A<float>, but I would also like to use it like A<std::complex<float>> and A<std::complex<double>>. When using the latter, I would like the definition of foo to look like
void foo(std::vector<std::complex<float>>& result);
and not like
void foo(std::vector<std::complex<std::complex<float>>>& result);
Is there any way to create a specific template for the std::complex<T> cases, in which I can access the "inner" type? Or this is not possible/bad practice?
What is the most elegant way to solve this issue?
Another way can pass through the creation of a type traits to detect the (extract, when needed) the float type
template <typename T>
struct getFloatType
{ using type = T; };
template <typename T>
struct getFloatType<std::complex<T>>
{ using type = T; };
and use it in A (see fT)
template <typename T>
class A
{
public:
using fT = typename getFloatType<T>::type;
void foo(std::vector<std::complex<fT>>& result)
{ }
};
You can make a partial specialization for any instantiation of std::complex, e.g.
template <typename T>
class A<std::complex<T>>
{
public:
void foo(std::vector<std::complex<T>>& result);
};
Then for A<std::complex<double>>, the signature of foo would be void foo(std::vector<std::complex<double>>& result);.
To handle those duplicated codes, you can make a base class and move the common members into it, and make the primary template and partial specialization both derive from it. e.g.
class Base {
public:
void bar(...);
};
then
template <typename T>
class A : public Base {
...
};
template <typename T>
class A<std::complex<T>> : public Base {
...
};
To define a friend of a templated class with a default argument, do you need to specify all friends as in the code below (which works)?
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
//...
};
// Vertex class
template <typename T>
class vertex {
//...
friend class graph<T, CIT_CHECK>;
friend class graph<T, CIT_FAST>;
friend class graph<T, CIT_GPU>;
friend class graph<T, CIT_SSE>;
};
I can imagine that there is a shorter way to denote that the friend is defined for all possible ClassImplType enum values. Something like friend class graph<T, ClassImplType>, but the latter doesn't work of course.
Apologies if the terminology I use is incorrect.
I can imagine that there is a shorter way to denote that the friend is defined for all possible ClassImplType enum values.
Sadly, there really isn't. You might try with
template<ClassImplType I> friend class graph<T, I>;
but the standard simply forbids one to befriend partial specializations:
§14.5.4 [temp.friend] p8
Friend declarations shall not declare partial specializations. [ Example:
template<class T> class A { };
class X {
template<class T> friend class A<T*>; // error
};
—end example ]
You can only either befriend them all:
template<class U, ClassImplType I>
friend class graph;
Or a specific one:
friend class graph<T /*, optional-second-arg*/>;
I can't see how befriending all possible specializations might cause a problem here, to be honest, but let's assume it does. One workaround I know would be using the passkey pattern, though we'll use a slightly cut-down version (we can't use the allow mechanism here, since it doesn't work well for allowing access to all specializations of a template):
template<class T>
class passkey{
passkey(){}
friend T;
// optional
//passkey(passkey const&) = delete;
//passkey(passkey&&) = delete;
};
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
template<class> struct vertex;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
public:
void call_f(vertex<T>& v){ v.f(passkey<graph>()); }
//...
};
// Vertex class
template <typename T>
class vertex {
//...
public:
template<ClassImplType I>
void f(passkey<graph<T,I>>){}
};
Live example with tests.
You'll note that you need to make all functionality that graph needs to access public, but that's not a problem thanks to the passkeys, which can only ever be created by the specified graph specializations.
You can also go farther and create a proxy class which can be used to access the vertex functionality (only graph changes):
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph{
typedef passkey<graph> key;
// proxy for succinct multiple operations
struct vertex_access{
vertex_access(vertex<T>& v, key k)
: _v(v), _key(k){}
void f(){ _v.f(_key); }
private:
vertex<T>& _v;
key _key;
};
public:
void call_f(vertex<T>& v){
vertex_access va(v, key());
va.f(); va.f(); va.f();
// or
v.f(key());
}
//...
};
Live example.
You can template the friend statement:
template<typename U, ClassImplType V>
friend class graph_foo;
I'm trying to figure out how to keep the T - I'll update if I find out.
I thought of the following way to 'fix it' by using recursive inheritance.
Inline comments explain what's happening:
#include <type_traits>
#include <string>
#include <iostream>
#include <typeinfo>
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES };
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph;
// Vertex class
namespace impl
{
template <typename, ClassImplType, typename enabler = void> struct vertex_impl;
///////////////////////////////////////////////////////////////
// actual implementation (stop condition of recursion)
static const ClassImplType CIT_ENDMARKER = (ClassImplType) -1;
template <typename T> struct vertex_impl<T, CIT_ENDMARKER>
{
protected: // make it protected rather than private
int secret() const { return 42; }
};
///////////////////////////////////////////////////////////////
// recursion, just to mark friends
template <typename T, ClassImplType impl_type>
struct vertex_impl<T, impl_type, typename std::enable_if<CIT_ENDMARKER != impl_type>::type>
: public vertex_impl<T, ClassImplType(impl_type - 1)>
{
friend class ::graph<T, impl_type>;
};
}
///////////////////////////////////////////////////////////////
// Public typedef
#if 1
template <typename T> struct vertex : impl::vertex_impl<T, CIT_NOF_TYPES> { };
#else // or c++11
template <typename T> using vertex = impl::vertex_impl<T, CIT_NOF_TYPES>;
#endif
template <typename T, ClassImplType impl_type>
class graph
{
public:
static void TestFriendOf(const vertex<T>& byref)
{
std::cout << byref.secret() << std::endl;
}
};
int main(int argc, const char *argv[])
{
vertex<int> t;
graph<int, CIT_CHECK> :: TestFriendOf(t);
graph<int, CIT_FAST> :: TestFriendOf(t);
graph<int, CIT_GPU> :: TestFriendOf(t);
graph<int, CIT_SSE> :: TestFriendOf(t);
graph<int, CIT_NOF_TYPES> :: TestFriendOf(t);
}
This works on gcc and clang.
See it live on http://liveworkspace.org/code/f03c0e25a566a4ca44500f4aaecdd354
PS. This doesn't exactly solve any verbosity issues at first sight, but you could make the solution more generic, and inherit from a different 'base-case' instead of the hard-coded one, in which case the boileplate could potentially be compensated for (in case you have many classes that need to befriend families of graph types)
Class cannot become friend of partial specialization according to this "non-bug" explanation: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=5094
What clenches it is that 14.5.3, p9
explicitly prohibits friend declarations of partial specializations:
-9- Friend declarations shall not declare partial specializations.
[Example:
template<class T> class A { };
class X {
template<class T> friend class A<T*>; // error
};
容nd example]
But I come to the solution, which does not look perfect, neither it is easy to use. The idea is to create intermediate friend inner class, just to forward "friendship" to outer class. The disadvantage (or advantage?) is that one has to wrap all function/member variables which shall be available to outer friend:
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
template <typename T>
class vertex;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
typedef typename vertex<T>::template graph_friend<impl_type> graph_friend;
public:
graph(vertex<T>& a) { graph_friend::foo(a); } // here call private method
//...
};
// Vertex class
template <typename T>
class vertex {
//...
int foo() {}
public:
template <ClassImplType impl_type>
class graph_friend {
static int foo(vertex& v) { return v.foo(); }
friend class graph<T,impl_type>;
};
};
int main() {
vertex<int> a;
graph<int,CIT_SSE> b(a);
}
I need to define a friend function for the templated class. The function has
return type that is a member type of the class. Now, I can not declare it beforehand, since the the return type is not known at the time. Something like this
template<class T> class A;
//This doesn't work: error: need ‘typename’ before...
template<class T> A<T>::member_type fcn(A<T>::member_type);
//This doesn't work: error: template declaration of ‘typename...
template<class T> typename A<T>::member_type fcn(A<T>::member_type);
template<class T>
class A{
public:
typedef int member_type;
friend member_type fcn<T>(member_type);
};
How do I do this?
I managed to compile that code on g++ using :
template<class T> typename A<T>::member_type fcn(typename A<T>::member_type);
(Thus a second 'typename' was required)
You need to say typename also in the argument:
template <class T>
typename A<T>::member_type fcn(typename A<T>::member_type);
// ^^^^^^^^
Otherwise there's no problem with your code, as long as all the template definitions appear before the function template is first instantiated.
It seems that in your particular example nothing in fcn function actually depends on class A. It doesn't even need to access any of the A's methods/fields, neither public nor protected/private. So it doesn't make sense. It would have made some sense otherwise, but at any rate it seems like it is worth re-thinking your problem and come up with a cleaner solution that does not need a hack like that. If, after a deep thought, you still believe you need it, you can do something like this:
#include <cstdio>
template<typename T> typename T::member_type fcn(const T & v) {
return v.value_;
}
template<class T>
class A {
public:
typedef T member_type;
friend member_type fcn< A<T> >(const A<T> &);
A() : value_(1986) {}
private:
T value_;
};
int main()
{
A<int> a;
printf("The value is: %d\n", fcn(a));
}
Notable thing in the above example is that you need to de-couple a cross dependency and make your free-function not depend on a declaration of class A. If you still feel like you need that coupling, the following code works, too:
#include <cstdio>
template <typename T>
class A;
template <typename T> typename A<T>::member_type fcn(const A<T> & v) {
return v.value_;
}
template <typename T>
class A {
public:
typedef int member_type;
friend member_type fcn<T>(const A<T> &);
A() : value_(1986) {}
private:
member_type value_;
};
int main()
{
A<void> a;
printf("The value is: %d\n", fcn(a));
}
Hope it helps. Good Luck!
This may by now be redundant with someone else's answer, but here's a complete, testable solution. The final function definition is a template specialization of fcn, which will produce a compiler error indicating that A<double>::x is not accessible from fcn<int>, but A<int>::x is accessible.
template<class T> class A;
template <typename U>
typename A<U>::member_type fcn(typename A<U>::member_type);
template<class T>
class A {
int x;
public:
typedef int member_type;
friend typename A<T>::member_type fcn<T>(typename A<T>::member_type);
};
template<>
int fcn<int>(int x)
{
A<int> i;
A<double> d;
i.x = 0; // permitted
d.x = 0; // forbidden
return 0;
}
is it possible to somehow make a partial template specification a friend class? I.e. consider you have the following template class
template <class T> class X{
T t;
};
Now you have partial specializations, for example, for pointers
template <class T> class X<T*>{
T* t;
};
What I want to accomplish is that every possible X<T*> is a friend class of X<S> for ANY S. I.e. X<A*> should be a friend of X<B>.
Of course, I thought about a usual template friend declaration in X:
template <class T> class X{
template <class S> friend class X<S*>;
}
However, this does not compile, g++ tells me this:
test4.cpp:34:15: error: specialization of 'template<class T> class X' must appear at namespace scope
test4.cpp:34:21: error: partial specialization 'X<S*>' declared 'friend'
Is this not possible at all or is there some workaround?
The reason why I am asking is that I need a constructor in X<T*> that creates this class from an arbitrary X<S> (S must be a subtype of T).
The code looks like this:
template <class T> class X<T*>{
T* t;
template<class S>
X(X<S> x) : t(&(x.t)) {} //Error, x.t is private
}
Now, the compiler complains, of course, that x.t is not visibile in the constructor since it is private. This is why I need a partial specialization friend class.
In C++, you can grant access beyond private on four levels.
completely public access (see pmr's answer)
access within inheritance hierarchy (protected, irrelevant here)
to a base template friend (see this answer)
to a non-template or fully specialized friend (too weak to solve your use case)
There is no middle way between the two latter kinds of friendship.
From §14.5.4 of the C++ standard:.
Friend declarations shall not declare partial specializations.
The following declaration will allow you to implement what you need. It gives you a free hand to access any specialization of your template from any other specialization, but still only within X. It is slightly more permissive than what you asked for.
template<class T> class X
{
template<class Any> friend class X;
public:
...
};
We can define a getter protected by a key defined in X.
#include <type_traits>
template <class T> class X{
T t;
public:
struct Key {
template<typename S>
Key(const X<S>&) {
static_assert(std::is_pointer<S>::value, "Not a pointer");
}
};
const T& get(Key) const { return t; }
T& get(Key) { return t; }
};
template <class T> class X<T*> {
T* t;
public:
template<class S>
X(X<S>& x) : t(&(x.get(typename X<S>::Key(*this)))) {}
};
int main()
{
X<int> x1;
X<int*> x2(x1);
return 0;
}
This still has some weakness. Everybody with an X<T*> can now use
get. But this is so obfuscated by now, that no one is goiing to
realize that. I'd choose a simple public getter.