Make all types have ValueLike traits by default.

This allows new types to be added without any fuzz (no need to specify
the traits) if it has operator>>. It also removes the need to manually
specify the ArgTrait for all built in types (such as long, bool, char,
float etc).

ArgTraits now works in the following way:

1) If there exists a specialization of ArgTraits for type X, use it.

2) If no specialization exists but X has the typename
X::ValueCategory, use the specialization for X::ValueCategory.

3) If neither (1) nor (2) defines the trait, use the default which is
ValueLike.
This commit is contained in:
Daniel Aarno 2013-05-18 15:01:46 +02:00
parent f41dcb5ce3
commit 5d4ffbf2db
8 changed files with 106 additions and 158 deletions

View File

@ -1,7 +1,8 @@
noinst_PROGRAMS = test1 test2 test3 test4 test5 test6 test7 test8 test9 \
test10 test11 test12 test13 test14 test15 test16 \
test17 test18 test19 test20 test21 test22 test23
test17 test18 test19 test20 test21 test22 test23 \
test24
test1_SOURCES = test1.cpp
test2_SOURCES = test2.cpp
@ -26,6 +27,7 @@ test20_SOURCES = test20.cpp
test21_SOURCES = test21.cpp
test22_SOURCES = test22.cpp
test23_SOURCES = test23.cpp
test24_SOURCES = test24.cpp
AM_CPPFLAGS = -I$(top_srcdir)/include

43
examples/test24.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "tclap/CmdLine.h"
#include <iterator>
using namespace TCLAP;
// Define a simple 3D vector type
struct Vect3D {
double v[3];
std::ostream& print(std::ostream &os) const
{
std::copy(v, v + 3, std::ostream_iterator<double>(os, " "));
return os;
}
};
// operator>> will be used to assign to the vector since the default
// is that all types are ValueLike.
std::istream &operator>>(std::istream &is, Vect3D &v)
{
if (!(is >> v.v[0] >> v.v[1] >> v.v[2]))
throw TCLAP::ArgParseException(" Argument is not a 3D vector");
return is;
}
int main(int argc, char *argv[])
{
CmdLine cmd("Command description message", ' ', "0.9");
ValueArg<Vect3D> vec("v", "vect", "vector",
true, Vect3D(), "3D vector", cmd);
try {
cmd.parse(argc, argv);
} catch(std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
vec.getValue().print(std::cout);
std::cout << std::endl;
}

View File

@ -73,13 +73,46 @@ struct ValueLikeTrait {
* Arg traits are used to get compile type specialization when parsing
* argument values. Using an ArgTraits you can specify the way that
* values gets assigned to any particular type during parsing. The two
* supported types are StringLike and ValueLike.
* supported types are StringLike and ValueLike. ValueLike is the
* default and means that operator>> will be used to assign values to
* the type.
*/
template<typename T>
struct ArgTraits {
typedef typename T::ValueCategory ValueCategory;
virtual ~ArgTraits() {}
//typedef ValueLike ValueCategory;
class ArgTraits {
// This is a bit silly, but what we want to do is:
// 1) If there exists a specialization of ArgTraits for type X,
// use it.
//
// 2) If no specialization exists but X has the typename
// X::ValueCategory, use the specialization for X::ValueCategory.
//
// 3) If neither (1) nor (2) defines the trait, use the default
// which is ValueLike.
// This is the "how":
//
// test<T>(0) (where 0 is the NULL ptr) will match
// test(typename C::ValueCategory*) iff type T has the
// corresponding typedef. If it does not test(...) will be
// matched. This allows us to determine if T::ValueCategory
// exists by checking the sizeof for the test function (return
// value must have different sizeof).
template<typename C> static short test(typename C::ValueCategory*);
template<typename C> static long test(...);
static const bool hasTrait = sizeof(test<T>(0)) == sizeof(short);
template <typename C, bool>
struct DefaultArgTrait {
typedef ValueLike ValueCategory;
};
template <typename C>
struct DefaultArgTrait<C, true> {
typedef typename C::ValueCategory ValueCategory;
};
public:
typedef typename DefaultArgTrait<T, hasTrait>::ValueCategory ValueCategory;
};
#endif

View File

@ -41,156 +41,10 @@
namespace TCLAP {
// ======================================================================
// Integer types
// ======================================================================
// Integer types (signed, unsigned and bool) and floating point types all
// have value-like semantics.
/**
* longs have value-like semantics.
*/
template<>
struct ArgTraits<long> {
typedef ValueLike ValueCategory;
};
/**
* ints have value-like semantics.
*/
template<>
struct ArgTraits<int> {
typedef ValueLike ValueCategory;
};
/**
* shorts have value-like semantics.
*/
template<>
struct ArgTraits<short> {
typedef ValueLike ValueCategory;
};
/**
* chars have value-like semantics.
*/
template<>
struct ArgTraits<char> {
typedef ValueLike ValueCategory;
};
#ifdef HAVE_LONG_LONG
/**
* long longs have value-like semantics.
*/
template<>
struct ArgTraits<long long> {
typedef ValueLike ValueCategory;
};
#endif
// ======================================================================
// Unsigned integer types
// ======================================================================
/**
* unsigned longs have value-like semantics.
*/
template<>
struct ArgTraits<unsigned long> {
typedef ValueLike ValueCategory;
};
/**
* unsigned ints have value-like semantics.
*/
template<>
struct ArgTraits<unsigned int> {
typedef ValueLike ValueCategory;
};
/**
* unsigned shorts have value-like semantics.
*/
template<>
struct ArgTraits<unsigned short> {
typedef ValueLike ValueCategory;
};
/**
* unsigned chars have value-like semantics.
*/
template<>
struct ArgTraits<unsigned char> {
typedef ValueLike ValueCategory;
};
// Microsoft implements size_t awkwardly.
#if defined(_MSC_VER) && defined(_M_X64)
/**
* size_ts have value-like semantics.
*/
template<>
struct ArgTraits<size_t> {
typedef ValueLike ValueCategory;
};
#endif
#ifdef HAVE_LONG_LONG
/**
* unsigned long longs have value-like semantics.
*/
template<>
struct ArgTraits<unsigned long long> {
typedef ValueLike ValueCategory;
};
#endif
// ======================================================================
// Float types
// ======================================================================
/**
* floats have value-like semantics.
*/
template<>
struct ArgTraits<float> {
typedef ValueLike ValueCategory;
};
/**
* doubles have value-like semantics.
*/
template<>
struct ArgTraits<double> {
typedef ValueLike ValueCategory;
};
// ======================================================================
// Other types
// ======================================================================
/**
* bools have value-like semantics.
*/
template<>
struct ArgTraits<bool> {
typedef ValueLike ValueCategory;
};
/**
* wchar_ts have value-like semantics.
*/
#ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
template<>
struct ArgTraits<wchar_t> {
typedef ValueLike ValueCategory;
};
#endif
/**
* Strings have string like argument traits.
*/
// Strings have string like argument traits.
template<>
struct ArgTraits<std::string> {
typedef StringLike ValueCategory;

View File

@ -81,7 +81,8 @@ TESTS = test1.sh \
test79.sh \
test80.sh \
test81.sh \
test82.sh
test82.sh \
test83.sh
EXTRA_DIST = $(TESTS) \
test1.out \
@ -165,6 +166,7 @@ EXTRA_DIST = $(TESTS) \
test79.out \
test80.out \
test81.out \
test82.out
test82.out \
test83.out
CLEANFILES = tmp.out

View File

@ -2,7 +2,7 @@
let "suc = 0"
let "fail = 0"
NUMTEST=82
NUMTEST=83
for (( tno = 1 ; $tno <= $NUMTEST ; tno = $tno + 1 )); do
./testCheck.sh $tno

1
tests/test83.out Normal file
View File

@ -0,0 +1 @@
1 2 3

13
tests/test83.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# this tests whether all required args are listed as
# missing when no arguments are specified
# failure
../examples/test24 -v "1 2 3" > tmp.out 2>&1
if cmp -s tmp.out $srcdir/test84.out; then
exit 0
else
exit 1
fi