template argument deduction failed in variadic template - c++

I'm writing a function that can pour the content of a string vector into variables. Here's what it looks like:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
template <typename T, int N = 0>
void pour2(std::vector<std::string> const& vals, T& val) {
std::stringstream ss;
ss << vals[N];
ss >> val;
}
template <typename T, typename ...Ts, int N = 0>
void pour2(std::vector<std::string> const& vals, T& val, Ts& ...args) {
std::stringstream ss;
ss << vals[N];
ss >> val;
pour2<Ts..., N+1>(vals, args...);
}
int main() {
std::vector<std::string> info = {"3", "1.5", "/home/tq/playground/"};
int sz;
double val;
std::string dir;
pour2(info, sz, val, dir);
std::cout << "size = " << sz << std::endl;
std::cout << "value = " << val << std::endl;
std::cout << "dir = " << dir << std::endl;
return 0;
}
However, g++-9.2 complains that
test.cpp: In instantiation of ‘void pour2(const std::vector<std::__cxx11::basic_string<char> >&, T&, Ts& ...) [with T = int; Ts = {double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >}; int N = 0]’:
test.cpp:30:26: required from here
test.cpp:18:19: error: no matching function for call to ‘pour2<double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, (0 + 1)>(const std::vector<std::__cxx11::basic_string<char> >&, double&, std::__cxx11::basic_string<char>&)’
18 | pour2<Ts..., N+1>(vals, args...);
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
test.cpp:7:6: note: candidate: ‘template<class T, int N> void pour2(const std::vector<std::__cxx11::basic_string<char> >&, T&)’
7 | void pour2(std::vector<std::string> const& vals, T& val) {
| ^~~~~
test.cpp:7:6: note: template argument deduction/substitution failed:
test.cpp:18:19: error: wrong number of template arguments (3, should be at least 1)
18 | pour2<Ts..., N+1>(vals, args...);
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
test.cpp:14:6: note: candidate: ‘template<class T, class ... Ts, int N> void pour2(const std::vector<std::__cxx11::basic_string<char> >&, T&, Ts& ...)’
14 | void pour2(std::vector<std::string> const& vals, T& val, Ts& ...args) {
| ^~~~~
test.cpp:14:6: note: template argument deduction/substitution failed:
and clang-9.0.1 says
test.cpp:18:2: error: no matching function for call to 'pour2'
pour2<Ts..., N+1>(vals, args...);
^~~~~~~~~~~~~~~~~
test.cpp:30:2: note: in instantiation of function template specialization 'pour2<int, double, std::__cxx11::basic_string<char> , 0>' requested here
pour2(info, sz, val, dir);
^
test.cpp:14:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Ts'
void pour2(std::vector<std::string> const& vals, T& val, Ts& ...args) {
^
test.cpp:7:6: note: candidate function template not viable: requires 2 arguments, but 3 were provided
void pour2(std::vector<std::string> const& vals, T& val) {
^
1 error generated.
I find that if I move the non-type template parameter to be the first argument, the code can compile and work as expected:
template <int N = 0, typename T>
void pour(std::vector<std::string> const& vals, T& val) {
std::stringstream ss;
ss << vals[N];
ss >> val;
}
template <int N = 0, typename T, typename ...Ts>
void pour(std::vector<std::string> const& vals, T& val, Ts& ...args) {
std::stringstream ss;
ss << vals[N];
ss >> val;
pour<N+1, Ts...>(vals, args...);
}
I just wonder, why it doesn't work in the first case?

If N appears after the parameter pack, N needs to be deduced from the function arguments or have default arguments, and N cannot be deduced by the functions argument.
"In a function template, the template parameter pack may appear earlier in the list provided that all following parameters can be deduced from the function arguments, or have default arguments". - [parameter_pack - cppreference]

Related

Error while trying to overload operator << for all std container printing, why?

I am trying to build an operator << overload to print all the standard library container types. So far, the overload works well, but when I use it in a generic program, it breaks when I try to print a simple std::string. In fact, this program:
#include <iostream>
#include <utility>
#include <vector>
#include <map>
#include <string>
// Helper Function to Print Test Containers (Vector and Map)
template <typename T, typename U>
inline std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p) {
out << "[" << p.first << ", " << p.second << "]";
return out;
}
template <template <typename, typename...> class ContainerType, typename
ValueType, typename... Args>
std::ostream& operator <<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
for (const auto& v : c) {
os << v << ' ';
}
return os;
}
int main()
{
std::vector <int> v = { 1,2,3 };
std::cout << v;
std::map <int,int> m = { { 1, 1} , { 2, 2 }, { 3, 3 } };
std::cout << m;
std::string s = "Test";
std::cout << s;
}
Gives me this error:
prove.cpp: In function ‘int main()’:
prove.cpp:32:13: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’})
32 | std::cout << s;
| ~~~~~~~~~ ^~ ~
| | |
| | std::string {aka std::__cxx11::basic_string<char>}
| std::ostream {aka std::basic_ostream<char>}
prove.cpp:16:15: note: candidate: ‘std::ostream& operator<<(std::ostream&, const ContainerType<ValueType, Args ...>&) [with ContainerType = std::__cxx11::basic_string; ValueType = char; Args = {std::char_traits<char>, std::allocator<char>}; std::ostream = std::basic_ostream<char>]’
16 | std::ostream& operator <<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
| ^~~~~~~~
In file included from /usr/include/c++/9/string:55,
from /usr/include/c++/9/bits/locale_classes.h:40,
from /usr/include/c++/9/bits/ios_base.h:41,
from /usr/include/c++/9/ios:42,
from /usr/include/c++/9/ostream:38,
from /usr/include/c++/9/iostream:39,
from prove.cpp:1:
/usr/include/c++/9/bits/basic_string.h:6419:5: note: candidate: ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
6419 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^~~~~~~~
I think that the problem is due to the fact that this overload is used to print also simple std::string objects, but I didn't find any suitable way to solve this so far. Any help? thanks.
Your operator<< overload may match types for which an operator<< overload is already defined. I suggest that you disable it for such types:
#include <type_traits>
template <template <typename, typename...> class ContainerType,
typename ValueType, typename... Args>
std::enable_if_t<!is_streamable_v<ContainerType<ValueType, Args...>>,
std::ostream&>
operator<<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
for (const auto& v : c) {
os << v << ' ';
}
return os;
}
The enable_if_t line uses SFINAE to disable the function for types that are already streamable.
The type trait is_streamable_v that is used above could look like this:
template<class T>
struct is_streamable {
static std::false_type test(...);
template<class U>
static auto test(const U& u) -> decltype(std::declval<std::ostream&>() << u,
std::true_type{});
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
// helper variable template:
template<class T>
inline constexpr bool is_streamable_v = is_streamable<T>::value;
Your original program should now work as expected:
int main() {
std::vector <int> v = { 1,2,3 };
std::cout << v;
std::map <int,int> m = { { 1, 1} , { 2, 2 }, { 3, 3 } };
std::cout << m;
std::string s = "Test";
std::cout << s;
}
Demo
The issue is that your << is too generic. It matches std::cout << some_string; and potentially other types for which there is already a << overload. The solution is to not provide overloads for types you do not own (unless it is explicitly permitted).
With minimal changes you can refactor your << to be a named function, then write a wrapper:
template <typename T>
struct my_print {
T& t;
};
template <typename T>
std::ostream& operator<<(std::ostream& out,const my_print<T>& mp) {
// call your named funtion template
do_the_printing(out,mp);
return out;
}
The caveat is that you need to explicitly create the instance:
std::cout << my_print(some_stl_container);
Of course you can also let your function template print directly and call it like this
do_the_print(std::cout,some_stl_container);

C++ Recursive Variadic Templates with extendes Base case

i want to use recursive variadic templates with a base case with more than 2 types. The following example does not compile. What could be the problem?
My expectation was that f<int, int>(5) would call a case like:
[with T = int; Arg = int; Args = {int}]
but that seems to be no option for the compiler (g++ c++17) ;)
template<class T, typename Arg, typename... Args>
void f(T a) {
}
template<class T, typename Arg>
void f (T a) {
}
int main() {
f<int, int>(5);
return 0;
}
<source>: In function 'int main()':
<source>:11:18: error: call of overloaded 'f<int, int>(int)' is ambiguous
11 | f<int, int>(5);
| ^
<source>:2:6: note: candidate: 'void f(T) [with T = int; Arg = int; Args = {}]'
2 | void f(T a) {
| ^
<source>:6:6: note: candidate: 'void f(T) [with T = int; Arg = int]'
6 | void f (T a) {
| ^
Compiler returned: 1
You can combine both cases and use a constexpr if statement in the function template:
#include <iostream>
template<class T, typename Arg, typename... Args>
void f(T a) {
std::cout << sizeof...(Args) << '\n';
if constexpr (sizeof...(Args) > 0) {
f<T, Args...>(a);
}
}
int main() {
f<int, int>(5);
std::cout << "---\n";
f<int, int, double, float, int>(5);
}
Output:
0
---
3
2
1
0

C++: operator<< Overloads not working

Because I am working on a mikrocontroller, where I don't have std::cout available, I want to define several operator<<() functions for my print class.
Because I have several print-backend-classes (one for each output channel e.g. uart, wireless, aso.), I wanted to define my operator<<() functions as templates.
But if I want to call this overloads, they don't work. I get compiler errors like
no match for ‘operator<<’ (operand types are ‘print_t’ and ‘gsl::basic_string_span<const char, -1>’)
I have the following Example:
#include <gsl/string_span>
template <typename T=char, std::size_t N>
constexpr gsl::cstring_span<> gen_cstring_span(const char (&a)[N]) noexcept {
return gsl::cstring_span<>(a, N);
}
class print_t {
public:
inline void append(const gsl::cstring_span<> buf) noexcept {
for(auto c : buf) {
printf("%c", c);
}
}
};
print_t p;
class prefix_t {
public:
static constexpr char prefix[] = "Prefix: ";
template<typename T>
print_t& operator<<(T&& arg) noexcept {
fprintf(stderr, "fwd, ");
p.append(prefix);
p << std::forward<T>(arg);
return p;
}
};
template<typename T>
using span_append_function_exists = std::is_member_function_pointer<decltype(static_cast<void(T::*)(const gsl::cstring_span<>)noexcept>(&T::append))>;
template<typename stream_t, std::enable_if_t<
span_append_function_exists<stream_t>::value, bool>>
stream_t& operator<<(stream_t& sb, const gsl::cstring_span<> str) noexcept {
sb.append(str);
fprintf(stderr, "cstring_span, ");
return sb;
}
template<typename stream_t, typename T=char, std::size_t N>
stream_t& operator<<(stream_t& sb, const char (&str)[N]) noexcept {
fprintf(stderr, "string_literal, ");
auto s = gen_cstring_span(str);
return sb << s;
}
template<typename stream_t>
stream_t& operator<<(stream_t& sb, const bool flag) noexcept {
fprintf(stderr, "bool, ");
if(flag) {
return sb << gen_cstring_span("true");
} else {
return sb << gen_cstring_span("false");
}
}
prefix_t pre;
int main() {
gsl::cstring_span<> span{gen_cstring_span("span")};
p << span << "\n";fprintf(stderr, "\n");
p << "string-literal" << "\n";fprintf(stderr, "\n");
p << true << "\n";fprintf(stderr, "\n");
pre << span << "\n";fprintf(stderr, "\n");
pre << "string-literal" << "\n";fprintf(stderr, "\n");
pre << true << "\n";fprintf(stderr, "\n");
}
This example should be C++17 (and was designed to work on a classic pc, but it should be ported to the MC.) and in this example, the print-backend-class would be print_t.
And each of the operator<<() functions has a template-parameter stream_t, which should become in this example the backend-class print_t.
I have worked with std::enable_if<>, to enable the sream_t param only on classes where the append() function is defined, but I did not succeed well.
Additionally, If I apply the operator on class prefix_t, it should print everything to the backend and additionally add a prefix-value before the output.
The expected STDOUT:
span
string-literal
true
Prefix: span
Prefix: string-literal
Prefix: true
The expected STDERR:
cstring_span,
string_literal, cstring_span,
bool, cstring_span,
fwd, cstring_span,
fwd, string_literal, cstring_span,
fwd, bool, cstring_span,
And a short part of the compiler errors:
tmp3.cpp: In function ‘int main()’:
tmp3.cpp:65:7: error: no match for ‘operator<<’ (operand types are ‘print_t’ and ‘gsl::cstring_span<> {aka gsl::basic_string_span<const char, -1>}’)
p << span << "\n";fprintf(stderr, "\n");
~~^~~~~~~
tmp3.cpp:36:11: note: candidate: template<class stream_t, typename std::enable_if<std::is_member_function_pointer<decltype (static_cast<void (T::*)(gsl::basic_string_span<const char, -1>) noexcept>(& T:: append))>::value, bool>::type <anonymous> > stream_t& operator<<(stream_t&, gsl::cstring_span<>)
stream_t& operator<<(stream_t& sb, const gsl::cstring_span<> str) noexcept {
^~~~~~~~
tmp3.cpp:36:11: note: template argument deduction/substitution failed:
tmp3.cpp:65:10: note: couldn't deduce template parameter ‘<anonymous>’
p << span << "\n";fprintf(stderr, "\n");
^~~~
tmp3.cpp:43:11: note: candidate: template<class stream_t, class T, long unsigned int N> stream_t& operator<<(stream_t&, const char (&)[N])
stream_t& operator<<(stream_t& sb, const char (&str)[N]) noexcept {
^~~~~~~~
tmp3.cpp:43:11: note: template argument deduction/substitution failed:
tmp3.cpp:65:10: note: mismatched types ‘const char [N]’ and ‘gsl::cstring_span<> {aka gsl::basic_string_span<const char, -1>}’
p << span << "\n";fprintf(stderr, "\n");
^~~~
tmp3.cpp:50:11: note: candidate: template<class stream_t> stream_t& operator<<(stream_t&, bool)
stream_t& operator<<(stream_t& sb, const bool flag) noexcept {
^~~~~~~~
tmp3.cpp:50:11: note: template argument deduction/substitution failed:
tmp3.cpp:65:10: note: cannot convert ‘span’ (type ‘gsl::cstring_span<> {aka gsl::basic_string_span<const char, -1>}’) to type ‘bool’
p << span << "\n";fprintf(stderr, "\n");
I am using C++17 with g++7.3.

method, that calls same-named method of all base classes, if exists and saves return value to a list

I am writing a macro, which generates helper methods to call all same-named methods of all base classes of a current class, and skip the base classes, that do not have methods of that name.
(I am not posting the actual macro, because I don't want to hurt anybody, below is my test file with one macro-generated method)
I managed to have it working without preserving the return values of these method.
Now I want to save the values and return a list.
Below is a function, generated by my macro, it is supposed to call methods named "base_method" of all bases, with int and string as arguments.
I don't understand, why I am getting the error (below the code).
#include <type_traits>
#include <list>
#include <iostream>
namespace detail{
template <typename> struct sfinae_true : std::true_type{};
}
namespace detail{
template <typename T, typename A1, typename A2>
static auto test_base_method(int) ->
sfinae_true<decltype(std::declval<T>().base_method(std::declval<A1>(), std::declval<A2>()))>;
template <typename , typename A1, typename A2>
static auto test_base_method(long) ->
std::false_type;
template <typename T, typename A1, typename A2>
struct has_base_method : decltype(test_base_method<T, A1, A2>(0)){};
template <typename Base, typename T, std::enable_if_t<has_base_method<Base,int,std::string>::value, bool> = true >
auto call_base_method_if_any(T& obj, int arg1, std::string arg2) ->
decltype( obj.Base::base_method(std::declval<int>(), std::declval<std::string>()))
{
return obj.Base::base_method(arg1, arg2);
}
template <typename Base, typename T, std::enable_if_t<!has_base_method<Base,int,std::string>::value, bool> = false>
auto call_base_method_if_any(T&, int, std::string) -> bool
{
return false;
}
};
template <typename ... T>
class Z : public T ... {
public:
auto call_base_method_of_all_bases_if_any(int arg1, std::string arg2) -> std::list<bool> {
return std::list<bool> { ( detail::call_base_method_if_any<T>(*this, arg1, arg2)) ... };
}
};
struct A{
bool base_method(int, bool){ std::cout << "A\n"; return true; }
bool base_method_narg(){ std::cout << "A no arg\n"; return true; }
};
struct B{ void base_method(int, bool){ std::cout << "B\n"; } };
struct C{ void base_method(int a, std::string b){ std::cout << "C, int = " << a << ", string = " << b; } };
struct D{ };
int main(){
Z<A> b;
Z<A,B> c;
Z<A,B,C> d;
Z<A,B,C,D> a;
std::cout << "a:" << std::endl;
auto x =a.call_base_method_of_all_bases_if_any(0, "string");
std::cout << std::endl;
std::cout << "b:" << std::endl;
b.call_base_method_of_all_bases_if_any(0, "string");
std::cout << std::endl;
std::cout << "c:" << std::endl;
c.call_base_method_of_all_bases_if_any(0, "string");
std::cout << std::endl;
std::cout << "d:" << std::endl;
d.call_base_method_of_all_bases_if_any(0, "string");
std::cout << std::endl;
}
Compiling errors:
g++ --std=c++14 expression_sfinae.3.cpp
expression_sfinae.3.cpp: In instantiation of ‘std::__cxx11::list<bool> Z<T>::call_base_method_of_all_bases_if_any(int, std::__cxx11::string) [with T = {A, B, C, D}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
expression_sfinae.3.cpp:48:63: required from here
expression_sfinae.3.cpp:27:99: error: no matching function for call to ‘std::__cxx11::list<bool>::list(<brace-enclosed initializer list>)’
return std::list<bool> { ( detail::call_base_method_if_any<T>(*this, arg1, arg2)) ... };
^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/list:63:0,
from expression_sfinae.3.cpp:2:
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:697:9: note: candidate: template<class _InputIterator, class> std::__cxx11::list<_Tp, _Alloc>::list(_InputIterator, _InputIterator, const allocator_type&)
list(_InputIterator __first, _InputIterator __last,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:697:9: note: template argument deduction/substitution failed:
expression_sfinae.3.cpp:27:74: note: cannot convert ‘detail::call_base_method_if_any<C, Z<A, B, C, D>, 1u>((*(Z<A, B, C, D>*)this), arg1, std::__cxx11::basic_string<char>(arg2))’ (type ‘void’) to type ‘const allocator_type& {aka const std::allocator<bool>&}’
return std::list<bool> { ( detail::call_base_method_if_any<T>(*this, arg1, arg2)) ... };
^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/list:63:0,
from expression_sfinae.3.cpp:2:
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:678:7: note: candidate: std::__cxx11::list<_Tp, _Alloc>::list(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = bool; _Alloc = std::allocator<bool>; std::__cxx11::list<_Tp, _Alloc>::allocator_type = std::allocator<bool>]
list(initializer_list<value_type> __l,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:678:7: note: candidate expects 2 arguments, 4 provided
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:667:7: note: candidate: std::__cxx11::list<_Tp, _Alloc>::list(std::__cxx11::list<_Tp, _Alloc>&&) [with _Tp = bool; _Alloc = std::allocator<bool>]
list(list&& __x) noexcept
^
u/5.3.0/include/g++-v5/bits/stl_list.h:697:9: note: template argument deduction/substitution failed:
expression_sfinae.3.cpp:27:74: note: cannot convert ‘detail::call_base_method_if_any<C, Z<A, B, C, D>, 1u>((*(Z<A, B, C, D>*)this), arg1, std::__cxx11::basic_string<char>(arg2))’ (type ‘void’) to type ‘const allocator_type& {aka const std::allocator<bool>&}’
return std::list<bool> { ( detail::call_base_method_if_any<T>(*this, arg1, arg2)) ... };
^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/list:63:0,
from expression_sfinae.3.cpp:2:
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:678:7: note: candidate: std::__cxx11::list<_Tp, _Alloc>::list(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = bool; _Alloc = std::allocator<bool>; std::__cxx11::list<_Tp, _Alloc>::allocator_type = std::allocator<bool>]
list(initializer_list<value_type> __l,
^
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:678:7: note: candidate expects 2 arguments, 4 provided
/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/include/g++-v5/bits/stl_list.h:667:7: note: candidate: std::__cxx11::list<_Tp, _Alloc>::list(std::__cxx11::list<_Tp, _Alloc>&&) [with _Tp = bool; _Alloc = std::allocator<bool>]
list(list&& __x) noexcept
^
// 9000 lines ommited
P.S. I also did not yet figured out how to deal with functions, that do not return anything (I don't think you can have a list of void). Any advices are welcome.
The root cause of the problem is that C's method returns void:
struct C {
void base_method(int a, std::string b);
^^^^^
};
And you're trying to use that return type to build up your std::list<bool>.
Going on the assumption that you'd want to exclude this case, I'd rewrite your details like so:
// this is the preferred overload (last argument is 'int' instead of '...')
// but will be SFINAE-d out if base_method() isn't callable with int or string
// or it returns something other than bool
template <class Base, class T,
class = std::enable_if_t<std::is_same<bool,
decltype(std::declval<Base&>().base_method(
std::declval<int>(),
std::declval<std::string>()))
>::value>>
bool call_base_method_if_any_impl(T& obj, int arg1, std::string arg2, int)
{
return obj.Base::base_method(arg1, arg2);
}
// fallback overload
template <class Base, class T>
bool call_base_method_if_any_impl(T& obj, int arg1, std::string arg2, ...) {
return false;
}
template <class Base, class T>
bool call_base_method_if_any(T& obj, int arg1, std::string arg2) {
return call_base_method_if_any_impl<Base>(obj, arg1, arg2, 0);
}

Variadic templates deduction error

I wrote a simple log function by c++0x variadic templates,
but there are templates deduction error,could somebody help me, thanks!
#ifndef SLOG_H
#define SLOG_H
enum LOGLEVEL{INFO, DEBUG, ERROR};
/* static */ const char* g_loglevel[] = {"INFO", "DEBUG", "ERROR"};
template <class T>
void slog_(const T& v) {
std::cout << v;
}
template <class T, class... Args>
void slog_(const T& v, const Args&... args) {
std::cout << v;
slog_(args...);
}
template <class T, class... Args>
void slog(LOGLEVEL level, const Args&... args) {
time_t t;
struct tm tm;
char buf[32];
time(&t);
localtime_r(&t, &tm);
strftime(buf, sizeof(buf), "%F %T", &tm);
std::cout << "[" << g_loglevel[level] << "][" << buf << "] ";
slog_(args...);
}
#endif
In call function:
slog(INFO, "hello, number ", n, ", next is ", n + 1);
then compile error:
main.cpp:6:53: error: no matching function for call to 'slog(LOGLEVEL, const char [15], int&, const char [11], int)'
main.cpp:6:53: note: candidate is:
In file included from main.cpp:2:0:
slog.h:19:6: note: template<class T, class ... Args> void slog(LOGLEVEL, const Args& ...)
slog.h:19:6: note: template argument deduction/substitution failed:
main.cpp:6:53: note: couldn't deduce template parameter 'T'
Thanks!
Change template <class T, class... Args> to template <class... Args> for slog. As the error message says: couldn't deduce template parameter 'T' because you never use it as a function parameter.