I'm trying to teach myself generic classes and functions declaration and Boost library at the sometime.
I've encountered an example and don't really understand what typename f=... means.
Could you help me to understand the concept of using template declaration with = sign in cases like: template <typename T, typename F=ublas::row_major>? Here is the full program that I'm trying to understand.
#include <algorithm>
#include <vector>
#include <boost/numeric/ublas/storage.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
namespace ublas = boost::numeric::ublas;
template <typename T, typename F=ublas::row_major>
ublas::matrix<T, F> makeMatrix(std::size_t m, std::size_t n, const std::vector<T> & v)
{
if(m*n!=v.size()) {
; // Handle this case
}
ublas::unbounded_array<T> storage(m*n);
std::copy(v.begin(), v.end(), storage.begin());
return ublas::matrix<T>(m, n, storage);
}
It is Default Argument that you are passing to Template.
e.g
Template<typename T, int N = 17>
class Generic
{
}
here, second Argument is default value
in youe case F=ublas::row_major is default value.
for deep understanding http://en.cppreference.com/w/cpp/language/template_parameters
It's a default value/type for the entry parameter of that template-d function. It's like compiler write down ublas::row_major everywhere you've written F, when you call makeMatrix without second template argument.
makeMatrix<int, int>( ... // Second parameter is `int`
makeMatrix<int> ( ... // Second is specified by default to `ublas::row_major`
To read more..
It is a default argument, which is used when nothing else is specified.
Related
I'm trying to figure out how to do a few things that seem to be tricky to me with regards to concepts and template type like std::vector.
I am trying to apply a compile time constraint similar to how I used std::movable on T, but on C with PushBackMovable. It works with the requires at the tail end of the function decl, but I would like to be consistent and put my constraints within the template args. I tried replacing "class C" with "PushBackMovable C", but that not so epically failed, but is closer to what I would prefer.
I'm trying to use the template types within the templated template parameter.
2a. Is there any way to just declare C and use the template args within it inside the signature of the
function? For example, can I remove "T" and "Alloc", and ride with "_T" and "_Alloc"? It seems
that I cannot access those parameters. I want to save some code space.
2b. Is their a way to remove the empty <> on C on the first arg of the operator?
2c. The compiler can deduce the template types of C on the requires if I just had PushBackMovable,
but then declval barfs. Are their any tricks I"m missing to implicitly determine template
parameters, specifically on the "C" instances? It would be nice to just say "C".
Is their an easier way to check for existence of a method than below?
Here is my example code for both cases:
#include <vector>
#include <type_traits>
#include <algorithm>
template<typename T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C >
concept PushBackMovable = std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(std::move(T{}))),void> &&
std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(T{})),void>;
template<std::movable T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C >
void operator+=( C<>& lhs, T rhs ) requires PushBackMovable<T, Alloc, C>
{
lhs.push_back( std::forward<T>( rhs ) );
}
int main() {
std::vector<int> ints;
int a = 5;
ints += 1;
ints += a;
std::copy(std::begin(ints), std::end(ints), std::ostream_iterator<int>(std::cout, " "));
}
Thank you for your help.
By using a template-template parameter you already constrain your function to containers that follow the standard library pattern but also to class templates that just happen to have two type template parameters. This is a strong constraint and usually useless in practice. That is, I would suggest that you instead operate on concrete types represented by a type template parameter, and let the concept verify any requirements that you would like to impose.
Additionally, don't use decltype with std::declval with std::is_same to check validity of an expression. Concepts have a dedicated syntax for that purpose, which is just putting this expression in braces.
One solution, merging what you want to verify in a single concept, could be as below:
#include <concepts>
#include <utility>
#include <type_traits>
template <typename C, typename T>
concept PushBackMovable = requires (C c, T t) {
{ c.push_back(t) } -> std::same_as<void>;
{ c.push_back(std::move(t)) } -> std::same_as<void>;
};
template <typename T, PushBackMovable<std::remove_reference_t<T>> C>
void operator+=(C& lhs, T&& rhs)
{
lhs.push_back(std::forward<T>(rhs));
}
DEMO
I'm using TBB library like this:
// Concurrency.hpp
#include <tbb/spin_mutex.h>
#include <tbb/mutex.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_reduce.h>
// Restrict templates to work for only the specified set of types
template<class T, class O = T>
using IntegerOnly = std::enable_if_t<std::is_integral<T>::value, O>;
// An extra helper template
template<class Fn, class I>
static IntegerOnly<I, void> loop_(const tbb::blocked_range<I> &range, Fn &&fn)
{
for (I i = range.begin(); i < range.end(); ++i) fn(i);
}
// Calling TBB parallel-for by this template
template<class It, class Fn>
static void for_each(It from, It to, Fn &&fn, size_t granularity = 1)
{
tbb::parallel_for(tbb::blocked_range{from, to, granularity}, // => Error happens at this line
[&fn, from](const auto &range) {
loop_(range, std::forward<Fn>(fn));
});
}
I'm receiving this error:
Concurrency.hpp:43:32: error: use of class template 'blocked_range' requires template arguments
blocked_range.h:45:7: note: template is declared here
Did anybody run into this error before? How to resolve it?
tbb::blocked_range is a class template, and you are attempting to use class template argument deduction (CTAD) by omitting any explicit template arguments when constructing it.
template<typename Value>
class blocked_range {
public:
//! Type of a value
/** Called a const_iterator for sake of algorithms that need to treat a blocked_range
as an STL container. */
typedef Value const_iterator;
// ...
//! Construct range over half-open interval [begin,end), with the given grainsize.
blocked_range( Value begin_, Value end_, size_type grainsize_=1 ) // ...
// ...
};
CTAD, however, is a C++17 feature, so if you are compiling with an earlier language version, you will need to specify the Value type template argument for the tbb::blocked_range class template. From above, we see that the Value type is expected as the iterator type, specifically the type of the first two arguments passed to its constructor, from and to in at the call site. Thus, you may modify your snippet as follows:
// Calling TBB parallel-for by this template
template<class It, class Fn>
static void for_each(It from, It to, Fn &&fn, size_t granularity = 1)
{
tbb::parallel_for(tbb::blocked_range<It>{from, to, granularity},
[&fn, from](const auto &range) {
loop_(range, std::forward<Fn>(fn));
});
}
From what you mention in your comments this may be a portability issue, and you may be likely to run into more issues after this one, and may want to consider looking over your project's compilation flags, so to see if you could possibly compile using C++17 instead.
The error says 'blocked_range' requires template arguments.
One solution is to add some template arguments. I've no idea what they should be but perhaps
tbb::blocked_range<I>{from, to, granularity}
^^^
template argument here
I'm trying to figure out how to do a few things that seem to be tricky to me with regards to concepts and template type like std::vector.
I am trying to apply a compile time constraint similar to how I used std::movable on T, but on C with PushBackMovable. It works with the requires at the tail end of the function decl, but I would like to be consistent and put my constraints within the template args. I tried replacing "class C" with "PushBackMovable C", but that not so epically failed, but is closer to what I would prefer.
I'm trying to use the template types within the templated template parameter.
2a. Is there any way to just declare C and use the template args within it inside the signature of the
function? For example, can I remove "T" and "Alloc", and ride with "_T" and "_Alloc"? It seems
that I cannot access those parameters. I want to save some code space.
2b. Is their a way to remove the empty <> on C on the first arg of the operator?
2c. The compiler can deduce the template types of C on the requires if I just had PushBackMovable,
but then declval barfs. Are their any tricks I"m missing to implicitly determine template
parameters, specifically on the "C" instances? It would be nice to just say "C".
Is their an easier way to check for existence of a method than below?
Here is my example code for both cases:
#include <vector>
#include <type_traits>
#include <algorithm>
template<typename T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C >
concept PushBackMovable = std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(std::move(T{}))),void> &&
std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(T{})),void>;
template<std::movable T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C >
void operator+=( C<>& lhs, T rhs ) requires PushBackMovable<T, Alloc, C>
{
lhs.push_back( std::forward<T>( rhs ) );
}
int main() {
std::vector<int> ints;
int a = 5;
ints += 1;
ints += a;
std::copy(std::begin(ints), std::end(ints), std::ostream_iterator<int>(std::cout, " "));
}
Thank you for your help.
By using a template-template parameter you already constrain your function to containers that follow the standard library pattern but also to class templates that just happen to have two type template parameters. This is a strong constraint and usually useless in practice. That is, I would suggest that you instead operate on concrete types represented by a type template parameter, and let the concept verify any requirements that you would like to impose.
Additionally, don't use decltype with std::declval with std::is_same to check validity of an expression. Concepts have a dedicated syntax for that purpose, which is just putting this expression in braces.
One solution, merging what you want to verify in a single concept, could be as below:
#include <concepts>
#include <utility>
#include <type_traits>
template <typename C, typename T>
concept PushBackMovable = requires (C c, T t) {
{ c.push_back(t) } -> std::same_as<void>;
{ c.push_back(std::move(t)) } -> std::same_as<void>;
};
template <typename T, PushBackMovable<std::remove_reference_t<T>> C>
void operator+=(C& lhs, T&& rhs)
{
lhs.push_back(std::forward<T>(rhs));
}
DEMO
is it possible to extend deduction rules in std?
#include <vector>
#include <array>
namespace std {
template< class T, size_t N >
vector(array<T, N>&) -> vector<T>;
}
int main() {
std::array a = {2,3,5,7}; // array<int, 4> !
std::vector w(a);
}
g++10.0 (wandbox) seems to ignore my version.
according to clang9.0 (Wandbox too) the predefined rule liv in a hidden space:
error: deduction guide must be declared in the same scope as template 'std::__1::vector'
No, you are not allowed to do this. Putting stuff into namespace std is allowed only in very rare cases, e.g. template specializations of std::hash for example. In your case, you can use class template argument deduction with a little bit more typing than desired:
std::array a = {2,3,5,7};
std::vector w(a.cbegin(), a.cend());
Note that the parentheses are crucial for initializing w, replacing them with braces deduces something quite different.
You can also factor the above constructor call out into a separate helper template:
template <class T, std::size_t N>
auto toVec(const std::array<T, N> a)
{
return std::vector(a.cbegin(), a.cend());
}
which allows for an initialization as
std::vector w = toVec(a);
Is there a standard way to get the types of a function's arguments and pass around these types as a template parameter pack? I know that this is possible in C++ because it has been done before.
I was hoping that with C++14 or the upcoming C++1z, there would be an idiomatic way to implement arg_types<F>... here:
template <typename ...Params>
void some_function(); // Params = const char* and const char*
FILE* fopen(const char* restrict filename, const char* restrict mode);
int main(){
some_function<arg_types<fopen>...>();
}
Just to be clear, an answer claiming that there is no standard way to do this is not an answer. If there is no answer, I would prefer that the question remain unanswered until the solution is added to C++500 or until the heat death of the universe, whichever happens earlier :)
Edit: A deleted answer noted that I can use PRETTY_FUNCTION to get the names of parameter types. However, I want the actual types. Not the names of those types.
This syntax is slightly different.
First, because types are easier to work with than packs, a type that holds a pack. The using type=types; just saves me work in the code that generates a types:
template<class...>struct types{using type=types;};
Here is the workhorse. It takes a signature, and produces a types<?...> bundle containing the arguments for the signature. 3 steps so we can get nice clean C++14esque syntax:
template<class Sig> struct args;
template<class R, class...Args>
struct args<R(Args...)>:types<Args...>{};
template<class Sig> using args_t=typename args<Sig>::type;
Here is a syntax difference. Instead of directly taking Params..., we take a types<Params...>. This is similar to the "tag dispatching" pattern, where we exploit template function type deduction to move arguments into the type list:
template <class...Params>
void some_function(types<Params...>) {
}
My fopen is different, because I don't want to bother #includeing stuff:
void* fopen(const char* filename, const char* mode);
And the syntax is not based off of fopen, but rather the type of fopen. If you have a pointer, you'd need to do decltype(*func_ptr) or somesuch. Or we could augment the top to handle R(*)(Args...) for ease of use:
template<class Sig>
struct args<Sig*>:args<Sig>{}; // R(*)(Args...) case
template<class Sig>
struct args<Sig&>:args<Sig>{}; // R(&)(Args...) case
then test code:
int main(){
some_function(args_t<decltype(fopen)>{});
}
live example.
Note that this does not work with overloaded functions, nor does it work with function objects.
In general, this kind of thing is a bad idea, because usually you know how you are interacting with an object.
The above would only be useful if you wanted to take a function (or function pointer) and pop some arguments off some stack somewhere and call it based off the parameters it expected, or something similar.
Inspired by #Yakk, here is a slightly simplified version:
First we define helper meta function to store function argment types as tuple.
template<typename Sig>
struct signature;
template<typename R, typename ...Args>
struct signature<R(Args...)>
{
using type = std::tuple<Args...>;
};
We use concept to restrict input as function
template<typename F>
concept is_fun = std::is_function_v<F>;
Here is our function "arguments" to retrieve input's argument types. Depends on input parameter, we overload "arguments" function to accept both reference and non reference.(free function is always passed by reference. We don't even have to have function body, only return type is enough as this is meta function.
template<is_fun F>
auto arguments(const F &) -> typename signature<F>::type;
Here is testing:
void foo(const string &, int, double)
{}
static_assert(std::is_same_v<decltype (arguments(foo)),
std::tuple<const string &, int, double>>);
My full-fledged version is here which also supports lambda, functor, member function pointer
Use Boost.FunctionTypes and std::index_sequence. Below is an example which prints the argument types of the function func. You can change the doit static function to do what you want. See it in action here.
template <typename FuncType>
using Arity = boost::function_types::function_arity<FuncType>;
template <typename FuncType>
using ResultType = typename boost::function_types::result_type<FuncType>::type;
template <typename FuncType, size_t ArgIndex>
using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type;
void func(int, char, double) {}
template <typename Func, typename IndexSeq>
struct ArgPrintHelper;
template <typename Func, size_t... Inds>
struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> >
{
static void doit()
{
string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...};
for (auto const& name : typeNames)
cout << name << " ";
cout << endl;
}
};
template <typename Func>
void ArgPrinter(Func f)
{
ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit();
}
int main()
{
ArgPrinter(func);
return 0;
}
Headers(moved down here to reduce noise in the above code snippet):
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <tuple>
#include <utility>
using namespace std;
For boost users, #include <boost/type_traits.hpp>
boost::function_traits<decltype(function)>::arg1_type
boost::function_traits<decltype(function)>::arg2_type
// boost::function_traits<decltype(function)>::argN_type
using FopenArg1 = boost::function_traits<decltype(fopen)>::arg1_type;
using FopenArg2 = boost::function_traits<decltype(fopen)>::arg2_type;
void some_function(FopenArg1, FopenArg2);
Boost Document
With a C++17 (or later) conforming compiler, you can use this:
#include<iostream>
template<typename type, typename...args>
void getFuncInfo(type(*func)(args...))
{
// some code here...
// here my example:
((std::cout << typeid(args).name() << "\n"),...);
}
// every Augments you can imagines...
void someRandomFunction(int a, float b, double c, const char* d, int e[], std::pair<int, const char*> f)
{
}
// test out in main.
int main()
{
getFuncInfo(someRandomFunction);
std::cin.get();
}