Is it possible to create template to the initialization like:
template <typename C> typename C::value_type fooFunction(C& c) {...};
std::vector<string> vec_instance;
fooFunction(cont<0>(vec_instance));
fooFunction(cont<1>(vec_instance));
In general i'm interested is it possible to specify template using integer (ie. 0) instead of true type name.
And how to achieve above?
I'm not completely clear on what you're asking, but the following snippet works for me:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename C>
typename C::value_type fooFunction(const C & c) { return 0; };
/* note that fooFunction takes a ref-to-const, not a reference */
template<int N>
struct cont
{
public:
typedef int value_type;
cont(vector<string> vec) {};
};
int main()
{
std::vector<string> vec_instance;
fooFunction(cont<0>(vec_instance));
fooFunction(cont<1>(vec_instance));
}
Two changes worth noting:
An integer is not a type, so if cont is declared template <typename T>, what you have written will not work. template <int N> is the proper way to parameterize over an integral value, as templatetypedef mentioned.
I'm not sure how cont<> is defined, but from your usage it must be an object you are constructing as a temporary. You will have trouble passing this temporary as a reference into fooFunction. Note that my example above passes C as reference-to-const instead.
Yes, you can parameterize templates over non-type arguments like integers, pointers, and other templates. For example:
template <typename T, int N> struct Array {
T data[N];
/* ... other functions ... */
};
These templates work just like all the other templates you've seen, except that they're parameterized over integral values rather than types.
This link has some more info on the subject. "Modern C++ Design" and "C++ Templates: The Complete Guide" also have lots of info on how to do this.
Is this what you are after? Non-type template parameters:
template<int n> class Cont
{
public:
typedef int value_type;
};
template<>
class Cont<0>
{
public:
typedef double value_type;
value_type convert(const std::string& s) const
{
return atof(s.c_str());
}
};
template<>
class Cont<1>
{
public:
typedef long value_type;
value_type convert(const std::string& s) const
{
return atoi(s.c_str());
}
};
template <int n> typename Cont<n>::value_type fooFunction(const Cont<n>& cont, const std::string& s)
{
return cont.convert(s);
}
void test()
{
Cont<0> c0;
Cont<1> c1;
double d = fooFunction(c0,"1.0");
int i = fooFunction(c1, "-17");
}
Related
In the code below, suppose that I decided to use deque instead of vector in the definition of mcc. How can I bypass cell.reserve(size) which is not defined for deque?
#include <vector>
#include <deque>
typedef std::vector<int> mcc;
//typedef std::deque<int> mcc;
void reserve(mcc& cell, int size)
{
cell.reserve(size);
}
int main()
{
mcc cell;
reserve(cell, 10);
return 0;
}
As the other answer and some comments have pointed out, in C++20, there are concepts, a feature which makes this task fairly trivial. However, as of now, C++20 support isn't complete in any compiler.
In the current C++ version, C++17, we don't have concepts. So, we need to use templates to emulate this concept behavior:
// The default case for can_reserve is false
template<typename T, typename = void>
struct can_reserve : std::false_type {};
// An overload of the struct allows us to verify we can call a value of type T
// If substitution doesn't fail, this overload is selected.
template<typename T>
struct can_reserve<T, std::void_t<decltype(std::declval<T>().reserve(1))>> : std::true_type {};
// With inline constexpr values, we can make this a type trait
template<typename T>
inline constexpr bool can_reserve_v = can_reserve<T>::value;
// We can then verify we can reserve with the types
static_assert(can_reserve_v<std::vector<int>>);
static_assert(!can_reserve_v<std::deque<int>>);
The function then becomes:
template<typename T>
void reserve(T& cell, int size)
{
if constexpr(can_reserve_v<T>)
cell.reserve(size);
}
Creating this kind of template is boilerplate-y and sometimes failure-prone. To solve that, we can use the detection idiom, which reduces the boilerplate and makes the code more readable:
// Using FluentCPP's is_detected implementation of the detection idiom
template<typename T>
using reserve_expression = decltype(std::declval<T&>().reserve(1));
template<typename T>
constexpr bool can_reserve_v = is_detected<reserve_expression, T>;
(The reserve function stays the same)
For completeness, the equivalent in C++20 would be:
template<typename T>
concept can_reserve = requires(T& t){
{ t.reserve(1) };
};
template<typename T>
void reserve(T& cell, int size)
{
if constexpr(can_reserve<T>)
cell.reserve(size);
}
There is a neat C++20 solution:
#include <vector>
#include <deque>
//typedef std::vector<int> mcc;
typedef std::deque<int> mcc;
mcc cell;
template<typename T>
void reserve(T& cell, int size)
{
if constexpr(requires{cell.reserve(size);}) {
cell.reserve(size);
}
}
int main()
{
reserve(cell, 10);
return 0;
}
Extremely new to c++ however have a question regarding templates
Suppose I have a simple template class as defined below:
template<typename Collection>
class MySack {
private:
Collection c;
public:
typedef typename Collection::value_type value_type;
void add(const value_type& value) {
c.push_back(value);
}
};
The aim of the class being to accept any type of collection, and allow a user to insert the correct type of value for the specified typename Collection.
The obvious problem is that this is only going to work for types which have a push_back method defined, which means it would work with list however not with set.
I started reading about template specialization to see if that'd be any help, however I don't think this would provide a solution as the type contained within the set would have to be known.
How would this problem be approached in c++?
You can use std::experimental::is_detected and if constexpr to make it work:
template<class C, class V>
using has_push_back_impl = decltype(std::declval<C>().push_back(std::declval<V>()));
template<class C, class V>
constexpr bool has_push_back = std::experimental::is_detected_v<has_push_back_impl, C, V>;
template<typename Collection>
class MySack {
private:
Collection c;
public:
typedef typename Collection::value_type value_type;
void add(const value_type& value) {
if constexpr (has_push_back<Collection, value_type>) {
std::cout << "push_back.\n";
c.push_back(value);
} else {
std::cout << "insert.\n";
c.insert(value);
}
}
};
int main() {
MySack<std::set<int>> f;
f.add(23);
MySack<std::vector<int>> g;
g.add(23);
}
You can switch to insert member function, which has the same syntax for std::vector, std::set, std::list, and other containers:
void add(const value_type& value) {
c.insert(c.end(), value);
}
In C++11, you might also want to create a version for rvalue arguments:
void add(value_type&& value) {
c.insert(c.end(), std::move(value));
}
And, kind-of simulate emplace semantics (not truly in fact):
template <typename... Ts>
void emplace(Ts&&... vs) {
c.insert(c.end(), value_type(std::forward<Ts>(vs)...));
}
...
int main() {
using value_type = std::pair<int, std::string>;
MySack<std::vector<value_type>> v;
v.emplace(1, "first");
MySack<std::set<value_type>> s;
s.emplace(2, "second");
MySack<std::list<value_type>> l;
l.emplace(3, "third");
}
I started reading about template specialization to see if that'd be
any help, however I don't think this would provide a solution as the
type contained within the set would have to be known.
You can partially specialize MySack to work with std::set.
template <class T>
class MySack<std::set<T>> {
//...
};
However, this has the disadvantage that the partial specialization replaces the whole class definition, so you need to define all member variables and functions again.
A more flexible approach is to use policy-based design. Here, you add a template parameter that wraps the container-specific operations. You can provide a default for the most common cases, but users can provide their own policy for other cases.
template <class C, class V = typename C::value_type>
struct ContainerPolicy
{
static void push(C& container, const V& value) {
c.push_back(value);
}
static void pop(C& container) {
c.pop_back();
}
};
template <class C, class P = ContainerPolicy<C>>
class MySack
{
Collection c;
public:
typedef typename Collection::value_type value_type;
void add(const value_type& value) {
P::push(c, value);
}
};
In this case, it is easier to provide a partial template specialization for the default policy, because it contains only the functionality related to the specific container that is used. Other logic can still be captured in the MySack class template without the need for duplicating code.
Now, you can use MySack also with your own or third party containers that do not adhere to the STL style. You simply provide your own policy.
struct MyContainer {
void Add(int value);
//...
};
struct MyPolicy {
static void push(MyContainer& c, int value) {
c.Add(value);
}
};
MySack<MyContainer, MyPolicy> sack;
If you can use at least C++11, I suggest the creation of a template recursive struct
template <std::size_t N>
struct tag : public tag<N-1U>
{ };
template <>
struct tag<0U>
{ };
to manage precedence in case a container can support more than one adding functions.
So you can add, in the private section of your class, the following template helper functions
template <typename D, typename T>
auto addHelper (T && t, tag<2> const &)
-> decltype((void)std::declval<D>().push_back(std::forward<T>(t)))
{ c.push_back(std::forward<T>(t)); }
template <typename D, typename T>
auto addHelper (T && t, tag<1> const &)
-> decltype((void)std::declval<D>().insert(std::forward<T>(t)))
{ c.insert(std::forward<T>(t)); }
template <typename D, typename T>
auto addHelper (T && t, tag<0> const &)
-> decltype((void)std::declval<D>().push_front(std::forward<T>(t)))
{ c.push_front(std::forward<T>(t)); }
Observe that the decltype() part enable they (through SFINAE) only if the corresponding method (push_back(), insert() or push_front()) is enabled.
Now you can write add(), in the public section, as follows
template <typename T>
void add (T && t)
{ addHelper<C>(std::forward<T>(t), tag<2>{}); }
The tag<2> element make so the tag<2> addHelper() method is called, if available (if push_back() is available for type C), otherwise is called the tag<1> method (the insert() one) if available, otherwise the tag<0> method (the push_front() one) is available. Otherwise error.
Also observe the T && t and std::forward<T>(t) part. This way you should select the correct semantic: copy or move.
The following is a full working example
#include <map>
#include <set>
#include <list>
#include <deque>
#include <vector>
#include <iostream>
#include <forward_list>
#include <unordered_map>
#include <unordered_set>
template <std::size_t N>
struct tag : public tag<N-1U>
{ };
template <>
struct tag<0U>
{ };
template <typename C>
class MySack
{
private:
C c;
template <typename D, typename T>
auto addHelper (T && t, tag<2> const &)
-> decltype((void)std::declval<D>().push_back(std::forward<T>(t)))
{ c.push_back(std::forward<T>(t)); }
template <typename D, typename T>
auto addHelper (T && t, tag<1> const &)
-> decltype((void)std::declval<D>().insert(std::forward<T>(t)))
{ c.insert(std::forward<T>(t)); }
template <typename D, typename T>
auto addHelper (T && t, tag<0> const &)
-> decltype((void)std::declval<D>().push_front(std::forward<T>(t)))
{ c.push_front(std::forward<T>(t)); }
public:
template <typename T>
void add (T && t)
{ addHelper<C>(std::forward<T>(t), tag<2>{}); }
};
int main ()
{
MySack<std::vector<int>> ms0;
MySack<std::deque<int>> ms1;
MySack<std::set<int>> ms2;
MySack<std::multiset<int>> ms3;
MySack<std::unordered_set<int>> ms4;
MySack<std::unordered_multiset<int>> ms5;
MySack<std::list<int>> ms6;
MySack<std::forward_list<int>> ms7;
MySack<std::map<int, long>> ms8;
MySack<std::multimap<int, long>> ms9;
MySack<std::unordered_map<int, long>> msA;
MySack<std::unordered_multimap<int, long>> msB;
ms0.add(0);
ms1.add(0);
ms2.add(0);
ms3.add(0);
ms4.add(0);
ms5.add(0);
ms6.add(0);
ms7.add(0);
ms8.add(std::make_pair(0, 0L));
ms9.add(std::make_pair(0, 0L));
msA.add(std::make_pair(0, 0L));
msB.add(std::make_pair(0, 0L));
}
Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic
I have a sfinae class that tests whether a class is a parser rule (AXE parser generator library).
The axe::is_rule<P>::value should evaluate to true iff P satisfies parser rule requirements. A parser rule must have one of the following member functions, taking a pair of iterators and returning axe::result<Iterator>:
template<class Iterator>
axe::result<Iterator> P::operator()(Iterator, Iterator);
, or its specialization, or non-template for some type CharT
axe::result<CharT*> P::operator()(CharT*, CharT*);
, or const versions of the above. Theoretically, there can be more than one overloaded operator(), though in practice a test for a single operator() with one of the above signatures would suffice.
Unfortunately, current implementation of is_rule takes care of only some, but not all cases. There are some unfortunate classes, that fail the is_rule test:
#define AXE_ASSERT_RULE(T)\
static_assert(axe::is_rule<typename std::remove_reference<T>::type>::value, \
"type '" #T "' is not a rule");
For example, the following unfortunate types fail the test:
struct unfortunate
{
axe::result<const unsigned char*>
operator()(const unsigned char*, const unsigned char*);
};
AXE_ASSERT_RULE(unfortunate);
// or same using lambda
auto unfortunate1 = [](const unsigned char*, const unsigned char*)
->axe::result<const unsigned char*> {};
AXE_ASSERT_RULE(decltype(unfortunate1));
typedef std::vector<char>::iterator vc_it;
struct unfortunate2 { axe::result<vc_it> operator()(vc_it, vc_it) const; };
AXE_ASSERT_RULE(unfortunate2);
typedef axe::result<const char*> (unfortunate3)(const char*, const char*);
AXE_ASSERT_RULE(unfortunate3);
struct rule { template<class I> axe::result<I> operator()(I, I); };
class unfortunate4 : public rule {};
AXE_ASSERT_RULE(unfortunate4);
Current solution in AXE is to wrap those in a forwarding wrapper (class r_ref_t), which, of course, creates syntactic warts (after all, parser generator is all about syntactic sugar).
How would you modify the sfinae test in is_rule to cover the unfortunate cases above?
I think the API of is_rule is not sufficient. For example unfortunate is a rule only if used with iterators of type const unsigned char*. If you use unfortunate with const char*, then it doesn't work, and is thus not a rule, right?
That being said, if you change the API to:
template <class R, class It> struct is_rule;
then I think this is doable in C++11. Below is a prototype:
#include <type_traits>
namespace axe
{
template <class It>
struct result
{
};
}
namespace detail
{
struct nat
{
nat() = delete;
nat(const nat&) = delete;
nat& operator=(const nat&) = delete;
~nat() = delete;
};
struct any
{
any(...);
nat operator()(any, any) const;
};
template <class T>
struct wrap
: public any,
public T
{
};
template <bool, class R, class It>
struct is_rule
{
typedef typename std::conditional<std::is_const<R>::value,
const wrap<R>,
wrap<R>>::type W;
typedef decltype(
std::declval<W>()(std::declval<It>(), std::declval<It>())
) type;
static const bool value = std::is_convertible<type, axe::result<It>>::value;
};
template <class R, class It>
struct is_rule<false, R, It>
{
static const bool value = false;
};
} // detail
template <class R, class It>
struct is_rule
: public std::integral_constant<bool,
detail::is_rule<std::is_class<R>::value, R, It>::value>
{
};
struct unfortunate
{
axe::result<const unsigned char*>
operator()(const unsigned char*, const unsigned char*);
};
#include <iostream>
int main()
{
std::cout << is_rule<unfortunate, const unsigned char*>::value << '\n';
std::cout << is_rule<unfortunate, const char*>::value << '\n';
}
For me this prints out:
1
0
I made the rule slightly more lax than you specified: The return type only has to be implicitly convertible to axe::result<It>. If you really want it to be exactly axe::result<It> then just sub in std::is_same where I used std::is_convertible.
I also made is_rule derive from std::integral_constant. This can be very convenient for tag dispatching. E.g.:
template <class T>
void imp(T, std::false_type);
template <class T>
void imp(T, std::true_type);
template <class T>
void foo(T t) {imp(t, is_rule<T, const char*>());}
Let's say I have a template:
template <class N, class I>
void add(N* element, std::list<N*> & container, I (N::*f)() const,
std::string successmsg, std::string exceptmsg) {
//...
}
And I want to call it for a list of Base Class pointers to a derivative class.
add(newAirplane, airplanes, &Airplane::getRegistration,
"Added!", "Error: Existent!");
Airplane inherits from AirplaneType.
Of course, it doesn't compile, N is first defined as AirplaneType and then as Airplane.
I added a virtual getRegistration # AirplaneType but of course, the compiler gives out a vtable error.
What's the proper way to solve this? AirplaneType has no registration attribute and I'm not interested in it having one. I also wanted to avoid virtual getRegistration() const {return "";}
Any suggestions for good practice?
EDIT:
Thanks for answers, but still not working. I think I have found the remaining problem, but not its solution:
void Airline::addAirplane(AirplaneType* airplane) {
add(newAirplane, airplanes, &Airplane::getRegistration,
"Added!", "Error: Existent!");
}
The type of pointer received is AirplaneType, not Airplane.
airplanes is a list of AirplaneType pointers.
You need another template parameter, because you care about two different classes - the type of the pointer (and hence the member function you're going to call with it), and the type of the container:
#include <list>
struct AirplaneType {
};
struct Airplane : AirplaneType {
int check() const { return 3; }
};
template <typename T, typename U, typename I>
void add(T* element, std::list<U*> & container, I (T::*f)() const) {
container.push_back(element);
I i = (element->*f)();
}
int main() {
std::list<AirplaneType*> ls;
Airplane a;
add(&a, ls, &Airplane::check);
}
In this case my add function doesn't really use the fact that container is a list, so a more sensible version might be:
template <typename T, typename U, typename I>
void add(T* element, U & container, I (T::*f)() const) {
container.push_back(element);
I i = (element->*f)();
}
And then again, you could abstract further:
template <typename T, typename U, typename AUF>
void add(T element, U & container, AUF func) {
container.push_back(element);
typename AUF::result_type i = func(element);
}
... but that's slightly less convenient for the caller:
#include <functional>
add(&a, ls, std::mem_fun(&Airplane::check));
Any suggestions for good practice?
Don't create containers of raw pointers.
Edit: to get this working with a virtual function, with each of my options:
#include <list>
#include <functional>
#include <iostream>
struct AirplaneType {
virtual int check() const { return 0; }
};
struct Airplane : AirplaneType {
int check() const { std::cout << "check\n"; return 3; }
};
template <typename T, typename U, typename I>
void add(U* element, std::list<T*> & container, I (U::*f)() const) {
container.push_back(element);
I i = (element->*f)();
}
template <typename T, typename U, typename AUF>
void add2(T element, U & container, AUF func) {
container.push_back(element);
typename AUF::result_type i = func(element);
}
int main() {
std::list<AirplaneType*> ls;
Airplane a;
add(static_cast<AirplaneType*>(&a), ls, &AirplaneType::check);
add2(&a, ls, std::mem_fun(&AirplaneType::check));
}
Output is:
check
check
which shows that the override is correctly called even though the function pointer was taken to AirplaneType::check, not Airplane::check.
You need to add an additional template parameter for the common base since C++ does not handle contravariant types. That is, std::list<Airplane*> is an entirely different type from std::list<AirplaneType*>, and no implicit conversion can occur from the list of pointers to the most derived to the least derived.. So, effectively your add function would need to become:
template <class N, class I, class B>
void add(N* element, std::list<B*> & container, I (N::*f)() const,
std::string successmsg, std::string exceptmsg)