Related
I'm not sure if this is possible, but I would like to count the number of template arguments of any class like:
template <typename T>
class MyTemplateClass { ... };
template <typename T, typename U>
class MyTemplateClass2 { ... };
such that template_size<MyTemplateClass>() == 1 and template_size<MyTemplateClass2>() == 2. I'm a beginner to template templates, so I came up with this function which of course does not work:
template <template <typename... Ts> class T>
constexpr size_t template_size() {
return sizeof...(Ts);
}
because Ts can not be referenced. I also know that it might come to problems when handling variantic templates, but that is not the case, at least for my application.
Thx in advance
There is one...
° Introduction
Like #Yakk pointed out in his comment to my other answer (without saying it explicitly), it is not possible to 'count' the number of parameters declared by a template. It is, on the other hand, possible to 'count' the number of arguments passed to an instantiated template.
Like my other answer shows it, it is rather easy to count these arguments.
So...
If one cannot count parameters...
How would it be possible to instantiate a template without knowing the number of arguments this template is suppose to receive ???
Note
If you wonder why the word instantiate(d) has been stricken throughout this post,
you'll find its explanation in the footnote. So keep reading... ;)
° Searching Process
If one can manage somehow to try to instantiate a template with an increasing number of arguments, and then, detect when it fails using SFINAE (Substitution Failure Is Not An Error), it should be possible to find a generic solution to this problem... Don't you think ?
Obviously, if one wants to be able to also manage non-type parameters, it's dead.
But for templates having only typename parameters...
There is one...
Here are the elements with which one should be able to make it possible:
A template class declared with only typename parameters can receive any type as argument. Indeed, although there can have specializations defined for specific types,
a primary template cannot enforce the type of its arguments.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The above statement might no longer be true from C++20 concepts.
I cannot try ATM, but #Yakk seems rather confident on the subject. After his comment:
I think concepts breaks this. "a primary template cannot enforce the type of its arguments." is false.
He might be right if constraints are apply before the template instantiation. But...
By doing a quick jump to the introduction to Constraints and concepts, one can read, after the first code example:
"Violations of constraints are detected at compile time, early in the template instantiation process, which leads to easy to follow error messages."
To be confirmed...
It is perfectly possible to create a template having for sole purpose to
be instantiated with any number of arguments. For our use case here, it might contain only ints... (let's call it IPack).
It is possible to define a member template of IPack to define the Next IPack by adding an int to the arguments of the current IPack. So that one can progressively increase its number of arguments...
Here is maybe the missing piece. It is maybe something that most people don't realize.
(I mean, most of us uses it a lot with templates when, for example, the template accesses a member that one of its arguments must have, or when a trait tests for the existence of a specific overload, etc...)
But I think it might help in finding solutions sometimes to view it differently and say:
It is possible to declare an arbitrary type, built by assembling other types, for which the evaluation by the compiler can be delayed until it is effectively used.
Thus, it will be possible to inject the arguments of an IPack into another template...
Lastly, one should be able to detect if the operation succeeded with a testing trait making use of decltype and std::declval. (note: In the end, none of both have been used)
° Building Blocks
Step 1: IPack
template<typename...Ts>
struct IPack {
private:
template<typename U> struct Add1 {};
template<typename...Us> struct Add1<IPack<Us...>> { using Type = IPack<Us..., int>; };
public:
using Next = typename Add1<IPack<Ts...>>::Type;
static constexpr std::size_t Size = sizeof...(Ts);
};
using IPack0 = IPack<>;
using IPack1 = typename IPack0::Next;
using IPack2 = typename IPack1::Next;
using IPack3 = typename IPack2::Next;
constexpr std::size_t tp3Size = IPack3::Size; // 3
Now, one has a means to increase the number of arguments,
with a convenient way to retrieve the size of the IPack.
Next, one needs something to build an arbitrary type
by injecting the arguments of the IPack into another template.
Step 2: IPackInjector
An example on how the arguments of a template can be injected into another template.
It uses a template specialization to extract the arguments of an IPack,
and then, inject them into the Target.
template<typename P, template <typename...> class Target>
struct IPackInjector { using Type = void; };
template<typename...Ts, template <typename...> class Target>
struct IPackInjector<IPack<Ts...>, Target> { using Type = Target<Ts...>; };
template<typename T, typename U>
struct Victim;
template<typename P, template <typename...> class Target>
using IPInj = IPackInjector<P, Target>;
//using V1 = typename IPInj<IPack1, Victim>::Type; // error: "Too few arguments"
using V2 = typename IPInj<IPack2, Victim>::Type; // Victim<int, int>
//using V3 = typename IPInj<IPack3, Victim>::Type; // error: "Too many arguments"
Now, one has a means to inject the arguments of an IPack
into a Victim template, but, as one can see, evaluating Type
directly generates an error if the number of arguments does not
match the declaration of the Victim template...
Note
Have you noticed that the Victim template is not fully defined ?
It is not a complete type. It's only a forward declaration of a template.
The template to be tested will not need to be a complete type
for this solution to work as expected... ;)
If one wants to be able to pass this arbitrary built type to some detection trait one will have to find a way to delay its evaluation.
It turns out that the 'trick' (if one could say) is rather simple.
It is related to dependant names. You know this annoying rule
that enforces you to add ::template everytime you access a member template
of a template... In fact, this rule also enforces the compiler not to
evaluate an expression containing dependant names until it is
effectively used...
Oh I see ! ...
So, one only needs to prepare the IPackInjectors without
accessing its Type member, and then, pass it to our test trait, right ?
It could be done using something like that:
using TPI1 = IPackInjector<IPack1, Victim>; // No error
using TPI2 = IPackInjector<IPack2, Victim>; // No error
using TPI3 = IPackInjector<IPack3, Victim>; // No error
Indeed, the above example does not generate errors, and it confirms
that there is a means to prepare the types to be built and evaluate
them at later time.
Unfortunately, it won't be possible to pass these pre-configured
type builders to our test trait because one wants to use SFINAE
to detect if the arbitrary type can be instantiated or not.
And this is, once again, related to dependent name...
The SFINAE rule can be exploited to make the compiler silently
select another template (or overload) only if the substitution
of a parameter in a template is a dependant name.
In clear: Only for a parameter of the current template instantiation.
Hence, for the detection to work properly without generating
errors, the arbitrary type used for the test will have to be
built within the test trait with, at least, one of its parameters.
The result of the test will be assigned to the Success member...
Step 3: TypeTestor
template<typename T, template <typename...> class C>
struct TypeTestor {};
template<typename...Ts, template <typename...> class C>
struct TypeTestor<IPack<Ts...>, C>
{
private:
template<template <typename...> class D, typename V = D<Ts...>>
static constexpr bool Test(int) { return true; }
template<template <typename...> class D>
static constexpr bool Test(...) { return false; }
public:
static constexpr bool Success = Test<C>(42);
};
Now, and finally, one needs a machinery that will successively try
to instantiate our Victim template with an increasing number of arguments. There are a few things to pay attention to:
A template cannot be declared with no parameters, but it can:
Have only a parameter pack, or,
Have all its parameters defaulted.
If the test procedure begins by a failure, it means that the template must take more arguments. So, the testing must continue until a success, and then, continue until the first failure.
I first thought that it might make the iteration algorithm using template specializations a bit complicated... But after having thought a little about it, it turns out that the start conditions are not relevant.
One only needs to detect when the last test was true and next test will be false.
There must have a limit to the number of tests.
Indeed, a template can have a parameter pack, and such a template can receive an undetermined number of arguments...
Step 4: TemplateArity
template<template <typename...> class C, std::size_t Limit = 32>
struct TemplateArity
{
private:
template<typename P> using TST = TypeTestor<P, C>;
template<std::size_t I, typename P, bool Last, bool Next>
struct CheckNext {
using PN = typename P::Next;
static constexpr std::size_t Count = CheckNext<I - 1, PN, TST<P>::Success, TST<PN>::Success>::Count;
};
template<typename P, bool Last, bool Next>
struct CheckNext<0, P, Last, Next> { static constexpr std::size_t Count = Limit; };
template<std::size_t I, typename P>
struct CheckNext<I, P, true, false> { static constexpr std::size_t Count = (P::Size - 1); };
public:
static constexpr std::size_t Max = Limit;
static constexpr std::size_t Value = CheckNext<Max, IPack<>, false, false>::Count;
};
template<typename T = int, typename U = short, typename V = long>
struct Defaulted;
template<typename T, typename...Ts>
struct ParamPack;
constexpr std::size_t size1 = TemplateArity<Victim>::Value; // 2
constexpr std::size_t size2 = TemplateArity<Defaulted>::Value; // 3
constexpr std::size_t size3 = TemplateArity<ParamPack>::Value; // 32 -> TemplateArity<ParamPack>::Max;
° Conclusion
In the end, the algorithm to solve the problem is not that much complicated...
After having found the 'tools' with which it would be possible to do it, it only was a matter, as very often, of putting the right pieces at the right places... :P
Enjoy !
° Important Footnote
Here is the reason why the word intantiate(d) has been stricken at the places where it was used in relation to the Victim template.
The word instantiate(d) is simply not the right word...
It would have been better to use try to declare, or to alias the type of a future instantiation of the Victim template.
(which would have been extremely boring) :P
Indeed, none of the Victim templates gets ever instantiated within the code of this solution...
As a proof, it should be enough to see that all tests, made in the code above, are made only on forward declarations of templates.
And if you're still in doubt...
using A = Victim<int>; // error: "Too few arguments"
using B = Victim<int, int>; // No errors
template struct Victim<int, int>;
// ^^^^^^^^^^^^^^^^
// Warning: "Explicit instantiation has no definition"
In the end, there's a full sentence of the introduction which might be stricken, because this solution seems to demonstrate that:
It is possible to 'count' the number of parameters declared by a template...
Without instantiation of this template.
#include <utility>
#include <iostream>
template<template<class...>class>
struct ztag_t {};
template <template<class>class T>
constexpr std::size_t template_size_helper(ztag_t<T>) {
return 1;
}
template <template<class, class>class T>
constexpr std::size_t template_size_helper(ztag_t<T>) {
return 2;
}
template <typename T>
class MyTemplateClass { };
template <typename T, typename U>
class MyTemplateClass2 { };
template<template<class...>class T>
struct template_size:
std::integral_constant<
std::size_t,
template_size_helper(ztag_t<T>{})
>
{};
int main() {
std::cout << template_size<MyTemplateClass>::value << "\n";
std::cout << template_size<MyTemplateClass2>::value << "\n";
}
I know of no way without writing out the N overloads to support up to N arguments.
Live example.
Reflection will, of course, make this trivial.
° Before Reading This Post
This post does not answer to "How to get the number of parameters",
it answers to "how to get the number of arguments"...
It is let here for two reasons:
It might help someone who would have mixed up (like I did)
the meaning of parameters and arguments.
The techniques used in this post are closely related to the ones used
to produce the correct answer I've posted as a separate answer.
See my other answer for finding "the number of parameters" of a template.
The answer of Elliott looks more like what one usually does (though the primary template should be fully defined and "do something" IMHO). It uses a template specialization for when a template is passed as argument to the primary template.
Meanwhile, the answer of Elliott vanished...
So I've posted something similar to what he showed below.
(see "Generic Solution")
But, just to show you that you weren't that far from a working solution, and, because I noticed that you have used a function for your try, and, you declared this function constexpr, you could have written it like that:
Note
It is a 'fancy solution', but it works...
template <typename T> class MyTemplateClass {};
template <typename T, typename U> class MyTemplateClass2 {};
template <template <typename...> class T, typename...Ts>
constexpr const size_t template_size(T<Ts...> && v)
{
return sizeof...(Ts);
}
// If the target templates are complete and default constructible.
constexpr size_t size1 = template_size(MyTemplateClass<int>{});
constexpr size_t size2 = template_size(MyTemplateClass2<int, short>{});
// If the target templates are complete but NOT default constructible.
constexpr size_t size3 = template_size(decltype(std::declval<MyTemplateClass<int>>()){});
constexpr size_t size4 = template_size(decltype(std::declval<MyTemplateClass2<int, short>>()){});
Explanation
You said "because Ts can not be referenced", which is true and false, because of the way you made the declaration of template_size.
That is, a template template parameter cannot declare parameters itself (where you placed Ts in the declaration of the function template). It is allowed to do so to give a clue of what the template argument is expected to receive as argument, but it is not a declaration of a parameter name for the current template declaration...
(I hope it's clear enough) ;)
Obviously, it might be a little bit over complicated, but it worth knowing I think that such a construct is possible also... ;)
Generic Solution
template <typename T> class MyTemplateClass {};
template <typename T, typename U> class MyTemplateClass2 {};
template<typename T>
struct NbParams { static constexpr std::size_t Value = 0; };
template<template <typename...> class C, typename...Ts>
struct NbParams<C<Ts...>> { static constexpr std::size_t Value = sizeof...(Ts); };
constexpr size_t size1 = NbParams<MyTemplateClass<int>>::Value;
constexpr size_t size2 = NbParams<MyTemplateClass2<int, short>>::Value;
That is the regular way one does this kind of things... ;)
Consider the following structs:
//Implementations provided elsewhere
struct A { A(int i, double d, std::string s); /* ... */ };
struct B { B(double d1, double d2); /* ... */ };
I have two conversion classes whose template signatures look like:
TupleAs< A, int, double, std::string > via1 { ... };
ArrayAs< B, double, 2 > via2 { ... };
Predictably, TupleAs converts a triplet of int,double, and std::string values into an object of type A. Similarly, ArrayAs converts a pair of two double values into an object of type B. (And yes, there are reasons why I cannot call the A and B constructors directly.)
Improving the syntax
I would like to change the syntax so I can do the following:
TupleAs< A(int,double,std::string) > via1 { ... };
ArrayAs< B(double,2) > via2 { ... };
which, I think, is more descriptive of a conversion process. The TupleAs template declaration and corresponding partial specialization would look like this:
template <typename T> struct TupleAs;
template <typename T, typename ... Args>
struct TupleAs<T(Args...)> { ... };
Compiler errors
However, if I try to do something similar with the ArrayAs version:
template <typename T> struct ArrayAs;
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
I get the following errors in clang (3.6) when trying to instantiate it (ArrayAs< B(double,2)> test;):
typeAs.cpp:14:22: error: unknown type name 'N'
struct ArrayAs<T(U,N)>{
^
typeAs.cpp:14:10: warning: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
struct ArrayAs<T(U,N)>{
^~~~~~~~~~~~~~~
typeAs.cpp:13:45: note: non-deducible template parameter 'N'
template<typename T, typename U, unsigned N>
^
The gcc error diagnostic is a little different, but I won't post it here.
I admit that my templating skills should be better than they are, and I also concede that an analogous std::function<B(double,2)> declaration clearly is nonsense. But can someone tell me why the particular syntax I'm trying to achieve is not allowed? I looked through the C++14 standard and had trouble finding the relevant portion, and I'm having trouble interpreting the clang diagnostic message.
When you specialize TupleAs:
template <typename T, typename ... Args>
struct TupleAs<T(Args...)>
You are basically overloading the notation for a function. You are specializing on a function that takes Args... and returns a T. That is a type. You may not be using that function as a function, or really ever think about it as being a type, but that is what it is.
On the other hand, here:
template <typename T, typename U, unsigned N>
struct ArrayAs<T(U,N)> { ... };
There is no such thing as a function that takes N. It could take unsigned, but it can't take a value. There is just no such reasonable thing. From your example, B(double, 2) simply does not make sense. At best, you could write something that would allow:
template <unsigned N> using size_ = std::integral_constant<size_t, N>;
ArrayAs< B(double,size_<2>) >
Or even:
ArrayAs< B(std::array<double, 2>) >
since now we're back to using types everywhere. Whether you prefer that or not is personal preference.
The key here is that types are first-class citizens when it comes to all things template metaprogramming, and values should be avoided where possible.
template <typename T> struct ArrayAs;
template <typename T, typename U, std::size_t N>
struct ArrayAs<T(std::array<U,N>)> { ... };
works, as would:
template<class T>
struct to_array;
template<class T, size_t N>
struct to_array< T[N] > { using type = std::array<T, N>; };
template<class T>
using arr = typename to_array<T>::type;
then:
ArrayAs< Bob( arr<int[3]> ) > some_var;
live example.
Sadly, directly using ArrayAs< Bob( int[3] ) > doesn't work due to how arrays in function types decay to pointers.
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.
Hello guys (and happy new year!)
I'm writing a (not really) simple project in C++ (my first, coming from plain C). I was wondering if there is a way to simplify the definition for multiple functions having the same template pattern. I think an example would be better to explain the problem.
The context
Let's assume I have a "Set" class which represents a list of numbers, defined as
template <class T>
class Set {
static_assert(std::is_arithmetic<T>(), "Template argument must be an arithmetic type.");
T *_address;
...
}
So if I have an instance (say Set<double>) and an array U array[N], where U is another arithmetic type and N is an integer, I would like to be able to perform some operations such as assigning the values of the array to those of the Set. Thus I create the function template inside the class
template <class U, int N>
void assign(U (&s)[N]) {
static_assert(std::is_arithmetic<U>(), "Template argument must be an arithmetic type.");
errlog(E_BAD_ARRAY_SIZE, N == _size);
idx_t i = 0;
do {
_address[i] = value[i];
} while (++i < size);
}
The problem
As far as my tests went the code above works perfectly fine. However I find it REALLY REALLY ugly to see since I need the static_assert to ensure that only arithmetic types are taken as arguments (parameter U) and I need a way to be sure about the array size (parameter N). Also, I'm not done with the assign function but I need so many other functions such as add, multiply, scalar_product etc. etc.!
The first solution
I was wondering then if there is a prettier way to write this kind of class. After some work I've come up with a preprocessor directive:
#define arithmetic_v(_U_, _N_, _DECL_, ...) \
template <class U, idx_t N> _DECL_ \
{ \
static_assert(std::is_arithmetic<U>(),"Rvalue is not an arithmetic type."); \
errlog(E_BAD_ARRAY_SIZE, N == _size); \
__VA_ARGS__ \
}
thus defining my function as
arithmetic_v(U, N,
void assign(U (&value)[N]),
idx_t i = 0;
do {
_address[i] = value[i];
} while (++i < _size);
)
This is somehow cleaner but still isn't the best since I'm forced to lose the brackets wrapping the function's body (having to include the static_assert INSIDE the function itself for the template parameter U to be in scope).
The question
The solution I've found seems to work pretty well and the code is much more readable than before, but... Can't I use another construct allowing me to build an even cleaner definition of all the functions and still preserving the static_assert piece and the info about the array size? It would be really ugly to repeat the template code once for each function I need...
The thanks
I'm just trying to learn about the language, thus ANY additional information about this argument will be really appreciated. I've searched as much as I could stand but couldn't find anything (maybe I just couldn't think of the appropriate keywords to ask Google in order to find something relevant). Thanks in advance for your help, and happy new year to you all!
Gianluca
I strongly suggest against using macros, unless there is no way around them (a case I could think of is getting the line number for debugging purposes). From the Google C++ Style Guide (http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preprocessor_Macros):
Macros mean that the code you see is not the same as the code the compiler sees. This can introduce unexpected behavior, especially since macros have global scope.
I really don't see why you consider using a static_assert ugly. There is another way to ensure that a template is specialized only for some types using SFINAE.
template <class T, class Enable = void>
class X;
template <class T>
class X<T, typename std::enable_if<std::is_integral<T>::value>::type> {
};
and you could do this even prettier using a using statement (no pun intended):
template <class T>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value>::type;
template <class T, class Enable = void>
class X;
template <class T>
class X<T, enable_if_integral_t<T>> {
};
And now
X<int> x; // ok, int is integral
X<float> y; // compile error
SFINAE (Substitution failure is not an error) is a feature in C++ in which you don't get an error if a template specialization fails.
template <bool Cond, class T = void> struct enable_if. The type T is enabled as member type enable_if::type if Cond is true. Otherwise, enable_if::type is not defined. So for a float type is_integral is false and enable_if::type doesn't exist, so the template specialization
template <class T>
class X<T, typename std::enable_if<std::is_integral<T>::value>::type>
fails, but the generic template is used instead
template <class T, class Enable = void>
class X;
which is declared, but not defined.
This is useful as you can have more specializations like:
template <class T>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value>::type;
template <class T>
using enable_if_floating_t = typename std::enable_if<std::is_floating_point<T>::value>::type;
template <class T, class Enable = void>
class X;
template <class T>
class X<T, enable_if_integral_t<T>> {
};
template <class T>
class X<T, enable_if_floating_t<T>> {
};
Hope you find this at least interesting.
Happy new year!
Edit
Where should I put the <T, enable_if_integral_t<T>> in a function definition? I can only get this done with class templates...
For a function, the enable_if::type can be the return type. For example if f returns int, you can have:
#include <type_traits>
template <class T>
typename std::enable_if<std::is_integral<T>::value, int>::type f(T a) {
return 2 * a;
}
int main() {
f(3); // OK
f(3.4); // error
return 0;
}
and with using:
#include <type_traits>
template <class T, class Return = void>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value, Return>::type;
template <class T>
enable_if_integral_t<T, int> f(T a) {
return 2 * a;
}
int main() {
f(3); // OK
f(3.4); // Error
return 0;
}
I don't understand why you consider the static_assert or errlog statements so ugly, and suspect it's partly unfamiliarity with the language. Still, you could easily write a function or macro (if you want to use __LINE__ inside the assign etc. function), to move them out of line, allowing usage like:
template <class U, int N>
void assign(U (&s)[N]) {
assert_array_n_numbers(s);
idx_t i = 0;
do {
_address[i] = s[i];
} while (++i < size);
}
Can't I use another construct allowing me to build an even cleaner definition of all the functions and still preserving the static_assert piece and the info about the array size? It would be really ugly to repeat the template code once for each function I need...
In terms of what's possible - though IMHO likely undesirable obfuscation - you could have your functions accept (an) argument(s) that has a templated implicit constructor from an array, verifying it's arithmetic in that constructor then verifying size in the function using it, allowing usage like:
template <typename U>
void assign(Arithmetic_Array<U>& s) {
assert_same_size(s);
idx_t i = 0;
do {
_address[i] = s[i];
} while (++i < size);
}
Implementation:
template <typename T>
class Arithmetic_Array
{
public:
template <size_t N>
Arithmetic_Array(T (&a)[N])
: p_(&a), size_(N)
{
static_assert(std::is_arithmetic<T>(),"Rvalue is not an arithmetic type.");
}
T& operator[](size_t i) { return p_[i]; }
const T& operator[](size_t i) const { return p_[i]; }
size_t size() const { return size_; }
private:
T* p_;
size_t size_;
};
Discussion
"cleaner" can be subjective. In particular, you should consider the value of "normal" non-macro using-the-intuitive-type C++ source as documentation and for maintainability. If a macro substantially simplifies many functions - and particularly if it's only used in an implementation file and not a shared header - then it's worthwhile, but if there's only marginal benefit it's not worth the obfuscation and de-localisation. All that template stuff might seem convoluted and ugly when you're new to the language, but after a while it's understood at a glance and helps readers understand what the function goes on to do.
It's also common in C++ to embrace a "duck typing" attitude to template's parametric polymorphism. That means that you can let people pass in arguments of whatever type, and if those types support the operations that the template implementation attempts on them (i.e. compile), then hopefully it'll be what the caller wants. That's one reason that it's a good idea to create types that have predictable semantic behaviour, for example - only using operator overloading when the affect is similar to the same operators on built in types or std::string.
The stricter enforcement you'd like has its place though - Bjarne Stroustrup and others have spent a lot of time working on "Concepts" which are a mechanism for enforcing expectations on types used as template parameters, and would have been a good fit for your "arithmetic types" stipulation here. I hope they'll make it into the next C++ Standard. Meanwhile, static assertions are a good way to go.
I have a templated matrix class that I explicitly instantiate for various POD types and custom class types. Some of the member functions however don't make sense for a few of such custom types. For example:
Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types? So far I have avoided the issue by making LoadFile a friend function and then explicitly controlling its instantiation. But I want to know if I can do this when LoadFile is a member function of Matrix.
The first question is whether you really need to control this. What happens if they call that member function on a matrix that stores My_custom_class? Can you provide support in your class (or the template) so that the member function will work?
If you really want to inhibit the use of those member functions for some particular type, then you can use specialization to block the particular instantiation:
template <typename T>
struct test {
void foo() {}
};
template <>
inline void test<int>::foo() = delete;
Or even just add static_asserts to the common implementation verifying the preconditions for what types is it allowed or disallowed?
template <typename T>
struct test {
void foo() {
static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
"Only allowed for int and double");
// regular code
}
};
with std::enable_if, this is the best I can come up with
template< typename T >
struct Matrix {
template< typename T >
Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()
only type int compile while other don't.
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types?
Your best bet here would be to use a static_assert that would create a compiler error when you attempt to call the method in a version of the class instantiated with a blocked type. Using std::enable_if, and other methods that would selectively "disable" a method itself would require you to create partial or full specializations of the class with and without the methods in question in order to prevent compiler errors. For instance, AFAIK, you cannot do the following:
template <typename T>
struct test
{
static const bool value = false;
};
template<>
struct test<double>
{
static const bool value = true;
};
template<typename T>
struct example
{
void print() { cout << "Printing value from print()" << endl; }
typename enable_if<test<T>::value, T>::type another_print()
{
cout << "Printing value from another_print()" << endl;
return T();
}
};
If you attempted to instantiate an example<int>, etc., you would end up with a compiler error at the point of instantiation of the object type. You couldn't simply call example<int>::print() and be okay, and only run into a problem if you chose to call example<int>::another_print(). Specializations of example<T> could get you around the issue, but that can be a bit of a mess. As originally surmised, a static_assert would probably be the easiest case to handle, along with a nice message to the end-user explaining what went wrong.
Keep in mind that creating compiler errors is the goal, and it's a good one to have. If you blocked a method from being instantiated, and the end-user decided to invoke it, you'd end up with a compiler error either way. The version without the static_assert will leave a lot of head-scratching as the user of your class attempts to parse a probably very verbose compiler error message, where-as the static_assert method is direct and to the point.
If the selected set of types is known at compile time, and you are using c++11 with a compiler that supports type aliases, uniform initialization and constexpr (for example gcc 4.7) you can make your code a bit cleaner like this (from previous example above by yngum):
template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template< typename T >
struct Matrix {
template< typename T >
//std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
Matrix<enable_if_t<std::is_integral<T>{}>>
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();
Beware of compatibility of this code, though, because these features have been only recently supported and some compilers don't do yet. You can see more about c++11 compiler support here.
If you could use the TypeLists from the ( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 ) - Loki you could implement something like:
template<bool>
struct Static_Assert;
template<>
struct Static_Assert<true>{};
class B{};
template<typename T>
class A{
public:
A(){
Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
}
};
Then your HasType would be something like:
template<typename T, typename TList>
struct HasType{
enum { value = 0+HasType< T, typename TList::Tail >::value };
};
template<typename T>
struct HasType< T, NullType >{
enum { value = 0 };
};
template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
enum { value = 1 };
};
In the list you can add the classes which you would like prevent to be passed as the template parameters.