If I have a complicated function that I want to use for two collections with matching interfaces (at least as far as the function in question is concerned) is there a way to just re-use the template code?
For example:
void DoSomethingIntense(std::vector<blah> myBlah);
void DoSomethingIntense(std::array<blah> myBlah);
If I use begin, end, size, and other functions that both array and vector have in common, is there a way to re-use the body of DoSomethingIntense without typing it twice (or, heaven forbid, stuffing it into a macro)?
(Please do not nitpick the example code, it doesn't help anybody)
UPDATE: My apologies, I neglected to mention that the function in question has other implementations for classes that do not match this signature; just making every argument use the code that works for these two is not an option.
I think the iterator solution might be best in that scenario.
Yes, use a template.
template <typename Container>
void DoSomethingIntense(Container blah) { // Might be better as Container const &
// write code using blah.begin() or whatever
}
You might be able to make it even more generic, following the example of STL, by supporting a general iterator range rather than specifically a container:
template <typename Iterator>
void DoSomethingIntense(Iterator begin, Iterator end);
Yes, you can achieve that by using templates:
template<typename T>
void DoSomethingIntense(const T &myBlah);
EDIT:
If I get your update right then I would say make use of SFINEA:
template<typename T>
struct is_vector : std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : std::true_type {};
template<typename T>
struct is_array : std::false_type {};
template<typename T, size_t N>
struct is_array<std::array<T, N>> : std::true_type {};
// add more if you want or define a macro
template<typename T>
std::enable_if_t<is_vector<T>::value || is_array<T>::value, void>
DoSomethingIntense(const T &myBlah)
{
}
int main()
{
std::vector<int> v;
DoSomethingIntense(v); // OK
std::array<float, 5> a;
DoSomethingIntense(a); // OK
std::queue<int> q;
DoSomethingIntense(q); // ERROR
}
You can mix templates / overloads. No problem.
For example:
template <typename T>
void DoSomethingIntense(T myBlah) {
}
void DoSomethingIntense(MyCustomClass myBlah) {
}
Then it will use the non-template version for argument type MyCustomClass and the template version for anything else (like vector or array)
Moreover, you can use std::enable_if to restrict the range of possible template arguments. See also this question.
Related
I have a template class where the template parameter corresponds to the size of an array within the class.
template <typename T, size_t S>
class Example {
...
private:
T values[S];
};
This leads to an expected warning: “ISO C++ forbids zero-size array.” In my case, something like Example<uint8_t, 0> would make no sense, and I would like to prevent the code containing Example<..., 0> from compiling.
How do I express in C++ that S should be superior or equal to one?
The C++20 way is
template <typename T, size_t S> requires (S > 0)
class Example
{
// ...
};
You're really trading in one compiler diagnostic for another, but here's one approach:
template <typename T, size_t S,
typename=std::enable_if_t< (S>0) >>
Alternatively: use static_assert to get a friendlier error message:
template <typename T, size_t S>
class Example {
private:
static_assert(S>0);
T values[S];
};
You'll get a friendlier error message however this template will still participate in overload resolution, which in some edge cases may be undesirable.
T values[0]; is alread ill-formed. Thus, if you configure the compiler to not use language extensions, then it won't compile.
Or, you can use a static_assert.
If there are situations where S being zero are valid. You can add a specialization for that case.
template<typename T, size_t S>
class Example {
...
private:
T values[S];
};
template<typename T>
class Example<T, 0> {
...
private:
// Don't need an array here for this case.
};
This will keep your code compiling in situations where you have heavy templating that makes S zero.
So I have the following (cut down) classes:
template <typename A, typename... B>
struct ComponentTupleAccessor:
public ComponentArray<A>,
public ComponentTupleAccessor<B...>
{
ComponentTupleAccessor(const uint32_t capacity):
ComponentArray<A>(capacity),
ComponentTupleAccessor<B...>(capacity)
{}
};
template <typename A>
struct ComponentTupleAccessor<A>:
public ComponentArray<A>
{
ComponentTupleAccessor<A>(const uint32_t capacity):
ComponentArray<A>(capacity)
{}
};
template <typename A, typename ...B>
class ComponentTuple {
ComponentTupleAccessor<A, B...> m_Components;
uint32_t m_Capacity;
public:
ComponentTuple(const RB32u capacity):
m_Capacity{capacity},
m_Components(capacity)
{}
template <typename S, typename ...T>
void pop_back() {
m_Components.Component<S>::pop_back();
pop_back<T...>();
}
template <typename S>
void pop_back() {
m_Components.Component<S>::pop_back();
}
void pop_back() {
pop_back<A, B...>();
}
};
The ComponentArray class is basically a wrapper around a vector that holds a bunch of components of a particular type.
The ComponentBlockTupleAccessor class more or less emulates a cut down version of std::tuple where the any number of unique types of ComponentArray can be inherited into the class ComponentTuple using the variadic templates.
The pop_back function in ComponentTuple is designed to recursively pop_back an element off each of the ComponentArrays.
Outside of the ComponentTuple class I'd like to be able to simply call something like compTupleInstance.pop_back() and all ComponentArray's should have their last elements removed.
I get a compile error "call of overloaded ‘pop_back()’ is ambiguous" pop_back();
I can't seem to figure out a combination of the A, B (pack), S, and T (pack) template parameters that gives me the functionality I need. What am I missing here?
Edit: Here is a simple usage scenario:
// ComponentTuple contains an int and a float ComponentArray with capacity 8.
ComponentTuple<int, float> dut(8);
// Push a set of new components to the ComponentArrays.
// This function has a similar structure to that of pop_back.
dut.push_back({8}, {3.141f});
// Another one
dut.push_back({4}, {2.718f});
// Remove the last element from all of the ComponentArrays.
dut.pop_back();
ComponentTuple template parameters will always be unique types, and there will always be greater than one.
A copy from the question:
template <typename S, typename ...T> // T can be empty
void pop_back() {
m_Components.Component<S>::pop_back();
pop_back<T...>();
}
template <typename S>
void pop_back() {
m_Components.Component<S>::pop_back();
}
If I invoke pop_back<A>() I have S = A. But, am I calling the first method with T empty, or am I calling the second method?
The core issue: template <typename S, typename ... T> and template <typename S> look equally good for the compiler when there is only one template argument (the pack can be empty). It cannot make a decision on which overload to use.
Solution: You can use fold expression (c++17 or above).
void pop_back() {
(m_Components.ComponentArray<A>::pop_back(), ... , m_Components.ComponentArray<B>::pop_back());
}
...Also the code breaks (even with the fold expression above) if used like this:
ComponentTuple<int, int, double> (ambiguous base class).
Thanks for your help guys, the ambiguity between <typename S> and <typename S, typename... T> seems obvious now that you've pointed it out. It seems it's just not possible to do it the way I was trying to, for that reason.
I ended up using a if constexpr to test if the recursion is at the last Type, so I can terminate the recursion at that point. I like this even better since in the non templated pop_back there is no risk of giving template parameters that weren't used in declaring the class. e.g.
ComponentTuple<int, float> dut(8);
push_back<Banana, char>; // Not int, float so should cause compile error.
Using the constexpr method, I can privatise the pop_back function (see pop_back_ below), and only expose the no-params version so that the method can only be called in the correct way:
template <typename A, typename ...B>
class ComponentTuple {
ComponentTupleAccessor<A, B...> m_Components;
uint32_t m_Capacity;
template <typename S, typename... T>
void pop_back_() {
m_Components.ComponentBlock<S>::pop_back();
if constexpr (sizeof...(T) > 0) {
pop_back_<T...>();
}
}
public:
ComponentTuple(const RB32u capacity):
m_Capacity{capacity},
m_Components(capacity)
{}
void pop_back() {
pop_back_<A, B...>();
}
};
Obviously I need to make sure I'm using at least c++17 to use if constexpr.
I have some function
template<typename T>
constexpr Foo make_foo<T>();
which essentially maps types to instances of Foo with no side-effects.
Now, I want to write the function magic,
template<typename Types...>
vector<Foo> magic();
which does the same as make_foo, but for variadic parameter packs; and in a way which it would then be easy for me to, say, stream all these Foo's to std::cout, or to iterate over them in a loop etc. I realize this question is not entirely well-defined, since I'm not clear if the relevant output I'm looking for is somekind of variadic packs of values (seeing how that doesn't exist in runtime).
So, what's the idiomatic way of doing that? I noticed that Eric Niebler has a blog page about a metaprogramming library which seems to be relevant, but it seems like a bit overkill. For my case.
If you need a vector of Foos, then it's just
template<typename Types...>
vector<Foo> magic(){
return { make_foo<Types>()... };
}
You can also throw them into a local array and play with them however you want:
Foo foos[] = { make_foo<Types>()... };
The standard way to access individual members of a parameter pack is via recursion, stripping off one or more members out of a time. In this case, we could make magic() a wrapper function, that passes the parameter pack to a worker function that in turn calls make_foo<T>(). So, assuming make_foo<T>() can only take a single type at a time, we would have something like this.
// Prototypes:
// -----
template<typename T>
constexpr Foo make_foo();
template<typename... Types>
std::vector<Foo> magic();
template<>
std::vector<Foo> magic<>();
template<typename T>
void magic_worker(std::vector<Foo>& vec);
template<typename T, typename U, typename... Types>
void magic_worker(std::vector<Foo>& vec);
// Actual code:
// -----
// The wrapper.
template<typename... Types>
std::vector<Foo> magic() {
std::vector<Foo> vec;
magic_worker<Types...>(vec);
return vec;
}
// Empty parameter pack.
template<>
std::vector<Foo> magic<>() {
return std::vector<Foo>(0);
}
// Only one type left.
template<typename T>
void magic_worker(std::vector<Foo>& vec) {
vec.push_back(make_foo<T>());
}
// At least two types left.
template<typename T, typename U, typename... Types>
void magic_worker(std::vector<Foo>& vec) {
vec.push_back(make_foo<T>());
magic_worker<U, Types...>(vec);
}
Not sure if this is the most efficient way to do what you want, but it should work. You can output the vector to std::cout via a range-based for loop, if you so desire.
std::vector<Foo> vec = magic</* args */>();
for (auto& a : vec) {
std::cout << a;
}
For a working example, see here.
Edit: If you're wondering why the recursive version of magic_worker() has two distinct template parameters before the pack, it's to remove ambiguity. As a template pack can have zero members, having one version take <typename T> and the other take <typename T, typename... Types> would confuse the compiler, and prevent your code from compiling. See here for more info.
If I have,
template<typename T1, typename T2, int N>
class X {};
Is there any way, that I can know class X has 3 template arguments ?
Use case in brief: There are two library classes ptr<T> (for normal pointer) and ptr_arr<T,N> (for pointer to array). These two are interacting with another class in following way:
template<typename T>
void Clear(const T &obj)
{
if(T::Args == 1) destroy(obj);
else destroy_arr(obj);
}
So, I thought if we have some handy way of knowing the number of parameters, it would make it easy. However, I learn that I need to change my business logic as there cannot be such way.
There is no standard way to do this (unless you use variadic sizeof(Args...) in C++0x) but that's beside the point -- the question is wrong.
Use overload resolution.
template <typename T>
void clear (ptr<T> & obj) {
destroy (obj);
}
template <typename T, int N>
void clear (ptr_arr<T,N> & obj) {
destroy_arr (obj);
}
You can use the mpl::template_arity (undocumented)
http://www.boost.org/doc/libs/1_40_0/boost/mpl/aux_/template_arity.hpp
There is no way to do this. Imagine the amount of overloads.
template<int> struct A;
template<bool> struct B;
template<char> struct C;
template<typename> struct D;
template<D<int>*> struct E;
template<D<bool>*> struct F;
template<typename, int> struct G;
// ...
For each of that, you would need a different template to accept them. You cannot even use C++0x's variadic templates, because template parameter packs only work on one parameter form and type (for example, int... only works for a parameter pack full of integers).
I need a template like this, which work perfectly
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
then i want to specialize the above template for std::string so i came up with
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
which doesnt't work, and throws an error. I would like to make the second example work and then IF possible i would like to add some code in the template to check if a std::vector/std::deque/std::list was used, to do something differently in each case.
So i used templates because 99% of the code is the same for both vectors and deques etc.
To specialize:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
To specialize for deque:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
Have you tried a template typename parameter? The syntax is a bit weird because it emulates the syntax used to declare such a container. There's a good InformIT article explaining this in more detail.
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
Notice that you also should declare the argument as a reference!
By the way: this comment
//check type of container
is a dead giveaway that you're doing something wrong. You do not want to check the type of the container. User more sophisticated overloading instead, as shown in sep's answer.
If I am understanding your problem correctly you have an algorithm that will work for STL containers vector, deque etc but are trying to write a template specialisation for string. If this is the case then you can write the generalised templated method that you defined in your question:-
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
Then for your string specialisation you declare:-
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
For any other specialisation just change the type declaration for myCont. If you really need to do this for the vector and deque containers then make the template parameter the parameter for the type in that container rather than the container itself as Sep suggested.
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
It's worth trying to avoid this by making your first implementation work with all STL containers to make your life easier, then you only need the specialisation for the string class. Even consider converting your string to a vector to avoid the specialisation all together.
On a side note, I've changed the container parameter to a const reference, I assume this is what you want, as you declare the object const anyway, this way you avoid a copy.
The answers so far seem helpful, but I think I'd use a different construct. I expect all containers to define value_type, just like the STL containers do. Therefore, I can write
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
In general, it's easier to act on a parameter that you've extracted explicitly.
#sep
'Simple' solution
The answer posted by 'sep' is pretty good, probably good enough for 99% of app developers, but could use some improvement if it's part of a library interface, to repeat:
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
This will work provided the caller isn't using std::vector. If this works well enough for you, to specialize for vector, list, etc, then stop here and just use that.
More complete solution
First, note that you can't partially specialize function templates -- you can create overloads. And if two or more of them match to the same degree, you will get "ambigous overload" errors. So we need to make exactly one match in every case you want to support.
One technique for doing this is using the enable_if technique -- enable_if allows you to selectively take function template overloads out of the possible match list using an obscure language rule... basically, if some boolean expression is false, the overload becomes 'invisible'. Look up SFINAE for more info if you're curious.
Example. This code can be compiled from the command line with MinGW (g++ parameterize.cpp) or VC9 (cl /EHsc parameterize.cpp) without error:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
Output:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
Whether it is a good design or not is left for further discussion. Anyway, you can detect the type of container using partial template specializations. In particular:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}