Enable member functions of class templates using concepts - c++

So I have a concept Fooable:
template <typename T>
concept bool Fooable()
{
return requires(...){ ... };
}
And I have a class template Bar that takes type T as template parameter and I want to enable a member function only if T is Fooable:
template <typename T>
class Bar
{
public:
template // ???
requires Fooable<T>
void MemFun();
};
Is it possible in C++17 with concepts TS or in C++2a?

In both the Concepts TS and C++20 designs, functions have an optional trailing requires-clause. So you don't need to make your member function a template to constrain it:
void MemFun() requires Fooable<T>;

Constraints can go after the function in the trailing position:
template <typename T>
class Bar
{
public:
void MemFun() requires Fooable<T>;
};
Live on Godbolt

Related

class template and member function template with requires

I have a template class called Speaker, with a template member function called speak. These both have a requires clause. How do I define the member function outside of the class in the same header file?
// speaker.h
#include <concepts>
namespace prj
{
template <typename T>
requires std::is_integral<T>
struct Speaker
{
template <typename U>
requires std::is_integral<U>
const void speak(const Speaker<U> &speaker);
};
// what do I put here?
const void Speaker<T>::speak(const Speaker<U> &speaker)
{
// code
}
}
The rules for defining template members of class templates are the same in principle as they were since the early days of C++.
You need the same template-head(s) grammar component(s), in the same order
template <typename T> requires std::is_integral_v<T>
template <typename U> requires std::is_integral_v<U>
const void Speaker<T>::speak(const Speaker<U> &speaker)
{
// code
}
The associated constraint expression and template <...> form the template-head together.
As an aside:
const qualified return types are redundant in the best case, or a pessimization in the worst case. I wouldn't recommend it (especially over void).
I'd also recommend using concepts (std::integral) if including the library header, not type traits (std::is_integral) that may or may not be included. The concepts allow for the abbreviated syntax, which is much more readable:
template<std::integral T>
template<std::integral U>

Member function of class with template arguments and default arguments outside class

I want to define function outside the template class as described below.
Already tried a lot of combinations for the second argument which is a template and takes default argument as well.
template <typename T>
class CustomAllocator
{
//My custom allocator
};
template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back();
};
/*I want to define push_back outside my class, tried everything.
Almost 4 hours spent through stackoverflow, fluentcpp and all sites*/
// What should be specified for Allocator here ?
template <typename T>
void CustomContainer<T,Allocator>::push_back(T value)
{
}
//OR
template <typename T>
void CustomContainer<T,CustomAllocator<> >::push_back(T value)
{
}
I expect it to be defined outside class
Actual getting compiler error, if it is simple type I could easily mention int,float etc. in the second argument.
Outside of your class definition, it will be unclear to a function what type Allocator is, so you have to redeclare it just like you redeclared T
template <class T, class Allocator>
void CustomContainer<T,Allocator>::push_back(T value)
{
// ...
}
(I'm assuming that DataType should be T)
Note that your declaration of push_back, in the class should match the definition:
template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back(T);
};
You may not use default template arguments for a member function of a template defined outside the template definition.
From the C++ 17 Standard (17.1 Template parameters)
... A default template-argument shall not be specified in the template-
parameter-lists of the definition of a member of a class
template that appears outside of the member’s class.
So just write
template <typename T, typename Allocator>
void CustomContainer<T, Allocator>::push_back( const T &value )
{
//...
}
Pay attention to the argument of the function. Your declaration of the function does not correspond to its definition.

Passing template prototype as template argument - is it possible?

So first, apologies for terminology - I'm not sure if template prototype is the correct term. By this I mean :
template <class T, class X>
class TemplatePrototype
{
// code
};
I have a situation where I have a function that creates a template object based upon template arguments to that function.
template <class T, class X>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
However, there are about 15 different versions of TemplatePrototype, which all have the same interface but different execution (TemplatePrototype is provided by another library). As a result, I have a lot of code that looks like this:
template <class T, class X>
void doSomethingWithOne()
{
TemplatePrototypeOne<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
template <class T, class X>
void doSomethingWithTwo()
{
TemplatePrototypeTwo<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
As a consequence of the architecture, I must know which TemplatePrototype I am going to use before I know the actual types T and X. I would like to see something like this:
template <class T, class X, class Prototype>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomething();
}
But where I have specified part of the template arguments in advance - i.e I specify Prototype before I know T and X. Obviously, this is not possible in C++.
Equally, I cannot pass the Prototype as a template argument because it will still result in huge amounts of duplicate code.
Some important facts : I know the range of all possible inputs.
So I could theoretically use a macro to define each possible template specialisation and insert them into a container, which I would then use to access the specialisation I need. However, I am looking for a more 'elegant' solution - is it possible to pass template prototypes without specialising them as an argument to a template class, and then instantiate later when a function is called? Example:
template <class Prototype>
class Holder
{
template <class T, class X>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomethingElse();
}
};
As far as I know this is impossible, but I was wondering if the SO community had some folks who know a solution?
EDIT:
So I have implemented this as my solution, thanks to the answers below!
#include <iostream>
template <typename T>
struct Foo
{
Foo() { aPtr = 0; }
T* aPtr;
};
template <template<typename> class C>
struct Bar
{
template <class T>
void doSomething()
{
C<T> aClass;
if (aClass.aPtr)
std::cout << "Hello world" << std::endl;
}
};
int main()
{
Bar<Foo> aFoo;
aFoo.doSomething<int>();
return 0;
}
This enables me to specify which TemplatePrototype I wish to use, before I can know the template parameters.
Yes, use a template template parameter, e.g.
template <typename T>
struct Foo
{
};
template <template<typename> class C>
struct Bar
{
};
then
Bar<Foo> b;
You're looking for template template parameters.
In the template parameter list, instead of just:
class TemplatePrototype
specify your prototype as a class template which itself has two template type parameters (without giving them a name here), like:
template<class,class> class TemplatePrototype
//^^^^^^^^^^^^^^^^^^^
This will result in a function like:
template <class T, class X,
template<class,class> class TemplatePrototype>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
Invocation example:
doSomething<T, X, TemplatePrototypeOne>();
To become independent of the number of template parameters you pass to your "prototype" (here it was 2, namely T and X), you can use variadic templates (since C++11).
For this, first move the prototype template parameter to the first position:
template <template<class,class> class TemplatePrototype,
class T, class X>
Then, replace class T, class X with class ...Ts, which is a placeholder of an arbitrary number of type parameters. Also, in the template template parameter list, replace class,class with class.... And in the instantiation within the function implementation, replace <T, X> with <Ts...> to "expand" the parameter pack.
The result then looks like this:
template <template<class...> class TemplatePrototype,
class ... Ts>
void doSomething()
{
TemplatePrototype<Ts...> aTemplateTs;
aTemplateTs.doSomethingElse();
}
Live demo

C++ - Overload templated class method with a partial specilization of that method

There are a few questions already similar to this already on stack overflow, but nothing that seemd to directly answer the question I have. I do apologise if I am reposting.
I'd like to overload a few methods of a templated class (with 2 template parameters) with a partial template specialisation of those methods. I haven't been able to figure out the correct syntax, and am starting to think that it's not possible. I thought I'd post here to see if I can get confirmation.
Example code to follow:
template <typename T, typename U>
class Test
{
public:
void Set( T t, U u );
T m_T;
U m_U;
};
// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
m_T=t;
m_U=u;
}
// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
m_T=t;
m_U=u+0.5f;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test<int, int> testOne;
int a = 1;
testOne.Set( a, a );
Test<int, float> testTwo;
float f = 1.f;
testTwo.Set( a, f );
}
I know that I could write a partial specialisation of the entire class, but that kinda sucks. Is something like this possible?
(I'm using VS2008)
Edit: Here is the compile error
error C2244: 'Test::Set' : unable to match function definition to an existing declaration
Thanks :)
You cannot partially specialize a member function without defining partial specialization of the class template itself. Note that partial specialization of a template is STILL a template, hence when the compiler sees Test<T, float>, it expects a partial specialization of the class template.
--
$14.5.4.3/1 from the C++ Standard (2003) says,
The template parameter list of a
member of a class template partial
specialization shall match the
template parameter list of the class
template partial specialization. The
template argument list of a member of
a class template partial
specialization shall match the
template argument list of the class
template partial specialization. A
class template specialization is a
distinct template. The members of the
class template partial specialization
are unrelated to the members of the
primary template. Class template
partial specialization members that
are used in a way that requires a
definition shall be defined; the
definitions of members of the primary
template are never used as definitions
for members of a class template
partial specialization. An explicit
specialization of a member of a class
template partial specialization is
declared in the same way as an
explicit specialization of the primary
template.
Then the Standard itself gives this example,
// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }
// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
I hope the quotation from the Standard along with the example answers your question well.
The particular problem you're sketching is easy:
template< class T >
inline T foo( T const& v ) { return v; }
template<>
float foo( float const& v ) { return v+0.5; }
Then call foo from your Test::Set implementation.
If you want the full generality, then similarly use a helper class with static helper member functions, and partially specialize that helper class.
Cheers & hth.,
There's also another solution to the partial specialization problem, if you don't want to introduce additional functions, methods or classes to your code.
#include <type_traits>
template <typename T1, typename T2>
class C
{
void f(T1 t1);
}
template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
if (std::is_same<T2, float>::value)
// Do sth
else
// Do sth
}

Lack of orthogonality in templates between class and function

// InternalTemplate.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
template<class T>
struct LeftSide
{
static void insert(T*& newLink, T*& parent)
{
parent->getLeft() = newLink;
newLink->parent = newLink;
}
};
template<class T>
struct Link
{
T* parent_;
T* left_;
T* right_;
T*& getParent()const
{
return parent_;
}
template<class Side>
void plugIn(Link<T>*& newLink);
};
template<class T>
template<class Side>
void Link<T>::plugIn(Link<T>*& newLink)//<<-----why can't I type
//void Link<T>::plugIn<Side>(Link<T>*& newLink)<---<Side> next to plugIn
{
Side::insert(newLink,this);
}
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
I find it strange that I have to specify parameter for a class but cannot specify parameter for a function. Is there any reason why?
Function templates and class templates are complementary (I call them orthogonal, but you are free not to agree), and in template metaprogramming they actually serve orthogonal purposes.
Class templates allow you to pattern match on the template argument, ie. they provide partial specialization.
Function templates, to the contrary, don't allow partial specialization, but they allow template argument deduction, which means you don't have to write the template arguments explicitly (except for extra arguments, as in your example).
This, I think, explains the differences in syntax since they are different in what they can achieve. Moreover, function templates can have overloads, class templates cannot.
The way to combine both concepts is
1) to have helper class templates with static non template functions if you want partial specialization for function templates:
template <typename T>
struct doSomethingWithPointersHelper
{
static void act(T x) { ... }
};
template <typename T>
struct doSomethingWithPointersHelper<T*>
{
static void act(T* x) { ... }
};
// This acts as if we had a partial specialization
// for pointer types
template <typename T>
doSomethingWithPointers(T x)
{ return doSomethingWithPointersHelper<T>::act(x); }
There are other ways to achieve this in particular cases, but this approach always works.
2) To have helper template functions if you want to make use of argument deduction when constructing complex classes:
template <typename T, typename U>
struct MyComplexClass
{ ... };
template <typename T, typename U>
MyComplexClass<T, U> makeComplex(T t, U u)
{ return MyComplexClass<T, U>(t, u); }
in the standard library, you find make_pair, bind1st or mem_fun which make use of this technique.
$14/2 -
A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the last component of the declarator-id shall be a template-name or operator-functionid (i.e., not a template-id). [ Note: in a class template declaration, if the class name is a simple-template-id, the declaration declares a class template partial specialization (14.5.5). —end note ]"
The standard forbids such a syntax explicitly. Refer this for more idea about template id / template name
You need to specialize on the Link struct in order to define it's template member function.
template<>
template<class Side>
void Link<int>::plugIn(Link<int>*& newLink)
{
Side::insert(newLink,this);
}
Gotta be honest, this makes my brain explode a little.