Re: how to make a simple generic function... parameterized by
collection & value
Am 17.05.2012 15:45, schrieb Mark Summerfield:
This is a followup to a mailing with the same subject. I had v.
helpful replies from wasti.r...@gmx.net and Daniel Kr?gler and have
now progressed to this:
template<typename T>
using Validator = std::function<T(*)(const std::string&)>;
This is an invalid specialization of std::function. Did you mean
std::function<T(const std::string&)> ?
template<typename C>
Validator<typename C::value_type>
makeSetValidator(const C&validItems,
Validator<typename C::value_type> validate)
{
return [=](const std::string&s)->typename C::value_type{
const auto&x = validate(s); // returns valid item of correct
This looks dangerous to me: You are binding here a temporary to a reference.
type or throws
if (std::find(std::begin(validItems), std::end(validItems),
x))
How should this be well-formed? std::find returns an iterator. Did you mean
if (std::find(std::begin(validItems), std::end(validItems), x) !=
std::end(validItems))
instead?
return x;
throw ValueError("Invalid item '" + s + "'");
};
}
The purpose of the code is to be able to supply a collection of valid
items and a per-item validation function and to get back a new
validation function. The returned function is expected to be called
with an item which must then be validated in two ways (1) by calling
the captured validate() function and (2) by ensuring that the item is
in the collection of valid items.
Unfortunately, although this compiles,
it doesn't work because
compilation fails at the call site. For example:
auto v = makeSetValidator<int>(std::set<int>{-4, 8, 31},
validate<int>);
The validate() function is a template function:
template<typename T>
T validate(const std::string&s) { ... }
This cannot work: You are forcing the compiler to deduce the template
parameter to be int, but you seems to expect a container-like type. The
explicit template-argument should be removed, because C should be
deduced to std::set<int>.
g++ 4.7.0 says:
main.cpp: In function ?void test9(const string&)?:
main.cpp:318:54: error: no matching function for call to
?makeSetValidator(std::set<int>,<unresolved overloaded function
type>)?
main.cpp:318:54: note: candidate is:
In file included from optarg_option.hpp:17:0,
from optarg.hpp:33,
from main.cpp:14:
optarg_validator.hpp:98:1: note: template<class C>
OptArg::Validator<typename C::value_type>
OptArg::makeSetValidator(const C&, OptArg::Validator<typename
C::value_type>)
optarg_validator.hpp:98:1: note: template argument deduction/
substitution failed:
optarg_validator.hpp: In substitution of ?template<class C>
OptArg::Validator<typename C::value_type>
OptArg::makeSetValidator(const C&, OptArg::Validator<typename
C::value_type>) [with C = int]?:
main.cpp:318:54: required from here
optarg_validator.hpp:94:58: error: ?int? is not a class, struct, or
union type
optarg_validator.hpp:94:58: error: ?int? is not a class, struct, or
union type
Note that it also fails if I provide a set<std::string> and use
validate<std::string> as the validator function.
Your code is plain buggy, but in addition there is also a gcc bug in
regard to non-deduced contexts, see:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52072
A workaround should be to introduce the following helper types
template<class T>
struct identity { typedef T type; };
template<class T>
using NonDeduced = typename identity<T>::type;
and to redeclare your function template as
template<typename C>
Validator<typename C::value_type>
makeSetValidator(const C& validItems,
NonDeduced<Validator<typename C::value_type>> validate);
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]