I'm hoping to get some feedback on a function with variadic templates that parses a format string and fills in some parameters whose order and types are based on the characters in the format string. Kind of like scanf().
(For the curious, I am trying to make a typesafe version of this function, documentation here.)
I'm pretty experienced with C but the last time I did anything serious with C++ was at university 15 years ago and it seems like a completely different language now.
This toy code works for me and fails in the ways I'd expect it to when I give it bad input. However, I'm not too familiar with the standard library so I have a strong feeling that I may be missing something. Also the code seems overly verbose for what it does.
So here's what I'm hoping to find out:
- Is this code idiomatic modern C++?
- Am I overlooking useful features in the standard library that would make things easier?
- Should I be using pointers in this way, or am I thinking too much in C?
- Should I consider another approach entirely, like
tscanf(format, paramname1, paramname2) >> param1 >> param2?
I am constrained to use C++11, the code currently does not use Boost.
#include <cstring>
#include <iostream>
struct SomeStruct {
int val;
};
template<typename T>
bool
assign(const char c, T& ref) {
return false;
}
template<>
bool
assign(const char c, bool*& ref) {
if (c != 'b')
return false;
*ref = true;
return true;
}
template<>
bool
assign(const char c, int*& ref) {
if (c != 'i')
return false;
*ref = 42;
return true;
}
template<>
bool
assign(const char c, SomeStruct& ref) {
if (c != 'h')
return false;
ref.val = 81;
return true;
}
template<typename T>
bool
tscanf(const char *format, const char *name, T& ref)
{
if (std::strlen(format) != 1) {
std::cerr << "Wrong number of arguments" << std::endl;
return false;
}
if (!assign(format[0], ref)) {
std::cerr << "Wrong type for argument " << name << std::endl;
return false;
}
return true;
}
template<typename T, typename... Args>
bool
tscanf(const char *format, const char *name, T& ref, Args... args)
{
if (!assign(format[0], ref)) {
std::cerr << "Wrong type for argument " << name << std::endl;
return false;
}
return tscanf(format + 1, args...);
}
int
main(void)
{
bool b;
int i;
SomeStruct h;
if (!tscanf("hbi",
"handle", h,
"switch", &b,
"num", &i))
return 1;
std::cout << h.val << ' ' << b << ' ' << i << std::endl;
return 0;
}