I am simply trying to output all of the parameters passed to a variadic function template. I tried this recursive approach:
#include <iostream>
template<typename TFirst, typename... Arguments>
void Output(TFirst first, Arguments... parameters)
{
std::cout << first << std::endl;
Output(parameters);
}
template<typename TFirst>
void Output(TFirst first)
{
std::cout << first << std::endl;
}
void Output()
{
// do nothing
}
int main()
{
Output(1.0f, 2);
}
but I get parameter packs not expanded with '...'. Can anyone explain what is wrong here?
--------- EDIT ------------
Here is the solution:
#include <iostream>
template<typename T>
inline void showArguments(T&& arg) { std::cout << arg << std::endl; }
template<typename First, typename... Rest>
inline void showArguments(First&& first, Rest&& ...rest)
{
showArguments(first);
showArguments(rest...);
}
int main()
{
showArguments("Hello", "World", 1, 2.3, false, true);
}
Should be
template<typename TFirst, typename... Arguments>
void Output(TFirst first, Arguments... parameters)
{
std::cout << first << std::endl;
Output(parameters...);
}
(note the trailing ... after the parameters)
Related
I'm trying to make a print function in C++ that takes in variable numbers of arguments and prints them each on their own line, like:
template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
std::cout << cur_line << '\n';
println(other_lines);
}
void println() { std::cout << std::flush; }
However, if Ty happens to be a std::vector<std::string>, I want to treat it differently (because I want to print every element of the vector on its own line). I looked into partial specialization, but there doesn't seem to be much that I could find on doing so with parameter packs. Here's what I tried:
template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
std::cout << cur_line << '\n';
println(other_lines);
}
template<typename... Types>
void println<std::vector<std::string>, Types...>
(std::vector<std::string> cur_line, Types... other_lines)
{
for (const auto& line : cur_line)
{
std::cout << line << '\n';
}
println(other_lines);
}
void println() { std::cout << std::flush; }
However, I'm getting an MSVC error C2768: "'println': illegal use of explicit template arguments".
Any suggestions or solutions would be warmly welcomed! For reference, I'm using Visual Studio 2019 Preview and its corresponding compiler version.
A simpler way would be to have a print function and overload that:
template < typename T >
void print(const T& line)
{
std::cout << line << '\n';
}
template < typename T >
void print(const std::vector<T>& line)
{
for (const auto& element : line)
{
print(element);
}
}
template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
print(cur_line);
println(other_lines);
}
void println() { std::cout << std::flush; }
You can do it like this:
/* main.cpp */
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <class T>
void PrintLine(const T &t)
{
cout << t << endl ;
}
template <class T>
void PrintLine(const vector<T> &t)
{
for(auto &obj : t ) PrintLine(obj);
}
template <class ... TT>
void PrintLines(const TT & ... tt)
{
( PrintLine(tt) , ... );
}
/* main() */
int main()
{
vector<string> list{"a","b","c"};
PrintLines(1,2,3,list);
return 0;
}
You can't partially specialize a function template, but you can overload it. Create a new overload of println that takes a std::vector<std::string> as the first argument and a general pack as the rest. Then do the special handling for the vector arg and forward the rest as before. Now your vectors will always be caught by the overload.
This question already has answers here:
How to make a variadic macro for std::cout?
(4 answers)
Closed 3 years ago.
I want to create a C++ Template for a function, that allows per default intinity arguments of any datatypes. I found some examples where they try to Code the printf function but it doesn't work (they included stdarg.h, i want something like that:)
//util.cpp
#include <iostream>
template<typename ...Args>
void debugPrint(Args... args)
{
// pseudo: foreach args as a:
std::cout << a;
// pseudo: endforeach
std::cout << std::endl;
}
//util.hpp
template<typename ...Args> //?
void debugPrint(Args...);
//app.cpp
#include "util.hpp"
int main()
{
debugPrint("Hallo", " ", "Welt", 1, 2, "\t", 2.3);
return 0;
}
Want the consoleoutput:
Hallo Welt12 [TAB] 2.3
Then there were an examplte with stdarg.h
#include <stdarg.h>
void tprintf(const char* format) // base function
{
std::cout << format;
}
template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // recursive function
{
for (; *format != '\0'; format++) {
if (*format == '%') {
std::cout << value;
tprintf(format + 1, Fargs...); // recursive call
return;
}
std::cout << *format;
}
}
So how? :(
Thanks for any answere <3
As with any recursive solution, you need a base case to terminate the recursion. In this situation the base case is when there are no arguments left to print, in which case you do nothing:
void debugPrint() { }
Then the recursive template function, which processes a single "first" argument and then recurses on the remaining variadic arguments:
template <typename FirstArg, typename ...Args>
void debugPrint(FirstArg arg, Args... args)
{
std::cout << arg;
debugPrint(args...);
}
Tying it all together:
#include <iostream>
void debugPrint() { }
template <typename FirstArg, typename ...Args>
void debugPrint(FirstArg arg, Args... args)
{
std::cout << arg;
debugPrint(args...);
}
int main()
{
debugPrint("Hallo", " ", "Welt", 1, 2, "\t", 2.3);
}
Outputs:
Hallo Welt12 2.3
You can use fold expressions to do that (C++17):
template<typename... Args>
void debugPrint(Args const&... args) {
(std::cout << ... << args);
}
It will expand args with a << between expanded expressions. There is no need for recursion.
Here's a live example.
I have the following pseudo code:
template <typename... Ts>
void f(int index) {
std::vector<std::function<void(void)>> funcs;
funcs.push_back([](){ std::cout << typeid(type_1).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_2).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_3).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_4).name() << std::endl; });
funcs[index]();
}
Imagine that the Ts... parameter pack holds type_1, type_2, type_3 and type_4.
how can I expand the parameter pack in order to achieve something like this? I mean - how can I get 4 push_back() calls if there are 4 parameters in the template pack, and also have the different types in the different lambdas? I don't know the syntax..
And can I actually get some sort of an array of such functions at compile time, so there are no push_backs at runtime?
C++17 solution is ok, but C++14 is best.
For C++17, something like this, I suppose
(funcs.push_back([](){ std::cout << typeid(Ts).name() << std::endl; }), ...);
or, better (IMHO), using emplace_back()
(funcs.emplace_back([](){ std::cout << typeid(Ts).name() << std::endl; }), ...);
But remeber that is
std::vector<std::function<void(void)>>
not
std::vector<std::function<void>>
In C++14 (and C++11) you can obtain something similar with the trick of intialization of the unused array; the function can be written as
template <typename ... Ts>
void f (int index)
{
using unused = int[];
std::vector<std::function<void(void)>> funcs;
(void)unused { 0, (funcs.emplace_back([]()
{ std::cout << typeid(Ts).name() << std::endl; }), 0)... };
funcs[index]();
}
Update.
From re-reading the question I think you just want to call the function once for the I'th type.
I which case it's trivial at compile time:
#include <array>
#include <type_traits>
#include <iostream>
#include <string>
template <class T>
void show_type()
{
std::cout << typeid(T).name() << std::endl;
}
template <typename... Ts>
void f(int index) {
using function_type = void(*)();
constexpr auto size = sizeof...(Ts);
constexpr std::array<function_type, size> funcs =
{
&show_type<Ts>...
};
funcs[index]();
}
int main()
{
for(int i = 0 ; i < 3 ; ++i)
f<int, double, std::string>(i);
}
example output:
i
d
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Something along these lines, perhaps:
template <typename... Ts>
void f(int index) {
int i = 0;
auto _ = {
(index == i++ ? ((std::cout << typeid(Ts).name() << std::endl) , 0) : 0) ...
};
}
Demo
If all you want to do is do something for the nth type in a template parameter pack, where n is a runtime variable, then the vector + function approach isn't really great. Better to add an index sequence in there and fold:
template <typename T> struct tag_t { using type = T; };
template <typename T> constexpr inline tag_t<T> tag{};
template <class F, size_t... Is, typename... Tags>
void match(F f, size_t i, std::index_sequence<Is...>, Tags... tags) {
auto inner = [&](auto tag) { f(tag); return true; };
bool matched = ((i == Is && inner(tags)) || ...);
if (!matched) {
// failure case?
}
}
template <typename... Ts, class F>
void match(F f, size_t i) {
return match(f, i, std::index_sequence_for<Ts...>(), tag<Ts>... );
}
template <typename... Ts>
void foo(int index) {
match<Ts...>([](auto tag){
std::cout << typeid(typename decltype(tag)::type).name() << std::endl;
}, index);
}
This construction allows you to add a failure case, where you might call the passed-in function with some special type:
struct failure { };
template <class F, size_t... Is, typename... Tags>
void match(F f, size_t i, std::index_sequence<Is...>, Tags... tags) {
auto inner = [&](auto tag) { f(tag); return true; };
bool matched = ((i == Is && inner(tags)) || ...);
if (!matched) {
f(failure{});
}
}
template <typename... Ts>
void foo(int index) {
match<Ts...>(overload(
[](auto tag){
std::cout << typeid(typename decltype(tag)::type).name() << std::endl;
},
[](failure ) { /* ... */ }
), index);
}
Consider the following code:
#include <utility>
#include <iostream>
struct S {
template<typename T, typename... A>
auto f(A&&... args) -> decltype(std::declval<T>().f(std::forward<A>(args)...), void()) {
std::cout << "has f(int)" << std::endl;
}
template<typename>
void f(...) {
std::cout << "has not f(int)" << std::endl;
}
};
struct T { void f(int) { } };
struct U { };
int main() {
S s;
s.f<T>(42); // -> has f(int)
s.f<U>(42); // -> has not f(int)
// oops
s.f<T>(); // -> has not f(int)
}
As shown in the example the third call to f works just fine, even if the number of arguments is wrong, for it's not wrong at all for the fallback function.
Is there a way to force the number of arguments when an ellipsis is involved that way?
I mean, can I check at compile time that the size of the arguments list is exactly 1, no matter if the main function or the fallback is chosen?
Good solutions are also the ones that only involves the first template function and result in hard-errors instead of soft-errors because of the size of the parameter pack.
Of course, it can be solved with several techniques without using variadic arguments. As an example: int/char dispatching on internal template methods; explicitly specify the arguments list; whatever...
The question is not about alternative approaches to do that, I already know them.
It's just to know if I'm missing something basic here or it's not possible and that's all.
If I understand correctly your issue, you may add a layer:
struct S {
private:
template<typename T, typename... A>
auto f_impl(A&&... args)
-> decltype(std::declval<T>().f(std::forward<A>(args)...), void()) {
std::cout << "has f(int)" << std::endl;
}
template<typename>
void f_impl(...) {
std::cout << "has not f(int)" << std::endl;
}
public:
template<typename T, typename A>
auto f(A&& args) { return f_impl<T>(std::forward<A>(arg)); }
};
With traits, you may do
template <typename T, typename ... Ts>
using f_t = decltype(std::declval<T>().f(std::declval<Ts>()...));
template <typename T, typename ... Ts>
using has_f = is_detected<f_t, T, Ts...>;
struct S {
template<typename T, typename... A>
std::enable_if_t<has_f<T, A&&...>::value && sizeof...(A) == 1> f(A&&... args)
{
std::cout << "has f(int)" << std::endl;
}
template<typename T, typename... A>
std::enable_if_t<!has_f<T, A&&...>::value && sizeof...(A) == 1> f(A&&... args) {
std::cout << "has not f(int)" << std::endl;
}
};
Demo
You can use a function (assert) that gets pointer to a function to deduce size of paramemters :
#include <utility>
#include <iostream>
template <typename...Args>
struct size_assert{
template <typename T,typename R,typename... Params>
constexpr static bool assert(R(T::*)(Params...) )
{
static_assert(sizeof...(Args) == sizeof...(Params),"Incorrect size of arguments!");
return true;
}
};
struct S {
template<typename T, typename... A, bool = size_assert<A...>::assert(&T::f)>
auto f(A&&... args) -> decltype(std::declval<T>().f(std::forward<A>(args)...), void())
{
std::cout << "has f(int)" << std::endl;
}
template<typename>
void f(...) {
std::cout << "has not f(int)" << std::endl;
}
};
struct T { void f(int) { } };
struct U { };
int main() {
// std::cout <<fc(&f);
S s;
s.f<T>(42); // -> has f(int)
s.f<U>(42); // -> has not f(int)
// oops
s.f<T>(); // -> has not f(int)
}
Can I use variadic templates without using the template parameters as function parameters?
When I use them, it compiles:
#include <iostream>
using namespace std;
template<class First>
void print(First first)
{
cout << 1 << endl;
}
template<class First, class ... Rest>
void print(First first, Rest ...rest)
{
cout << 1 << endl;
print<Rest...>(rest...);
}
int main()
{
print<int,int,int>(1,2,3);
}
But when I don't use them, it doesn't compile and complains about an ambiguity:
#include <iostream>
using namespace std;
template<class First>
void print()
{
cout << 1 << endl;
}
template<class First, class ... Rest>
void print()
{
cout << 1 << endl;
print<Rest...>();
}
int main()
{
print<int,int,int>();
}
Unfortunately the classes I want to give as template parameters are not instantiable (they have static functions that are called inside of the template function).
Is there a way to do this?
template<class First> // 1 template parameter
void print()
{
cout << 1 << endl;
}
#if 0
template<class First, class ... Rest> // >=1 template parameters -- ambiguity!
void print()
{
cout << 1 << endl;
print<Rest...>();
}
#endif
template<class First, class Second, class ... Rest> // >=2 template parameters
void print()
{
cout << 1 << endl;
print<Second, Rest...>();
}
Make it a type.
template <typename... Ts>
struct print_impl;
template <typename T>
struct print_impl<T> {
static void run() {
std::cout << 1 << "\n";
}
};
template <typename T, typename... Ts>
struct print_impl<T, Ts...> {
static void run() {
std::cout << 1 << "\n";
print_impl<Ts...>::run();
}
};
template <typename... Ts>
void print() {
print_impl<Ts...>::run();
}
int main() {
print<int, int, int>();
return 0;
}