Merge branch 'traits'

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.

Conflicts:
	examples/Makefile.am
	examples/test24.cpp
	tests/Makefile.am
	tests/runtests.sh
	tests/test83.out
	tests/test83.sh
This commit is contained in:
Daniel Aarno 2013-10-26 13:56:31 +02:00
commit bd0440fdbd
5 changed files with 96 additions and 154 deletions

42
examples/test26.cpp Normal file
View File

@ -0,0 +1,42 @@
#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 * Arg traits are used to get compile type specialization when parsing
* argument values. Using an ArgTraits you can specify the way that * argument values. Using an ArgTraits you can specify the way that
* values gets assigned to any particular type during parsing. The two * 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> template<typename T>
struct ArgTraits { class ArgTraits {
typedef typename T::ValueCategory ValueCategory; // This is a bit silly, but what we want to do is:
virtual ~ArgTraits() {} // 1) If there exists a specialization of ArgTraits for type X,
//typedef ValueLike ValueCategory; // 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 #endif

View File

@ -41,156 +41,10 @@
namespace TCLAP { namespace TCLAP {
// ====================================================================== // Integer types (signed, unsigned and bool) and floating point types all
// Integer types // have value-like semantics.
// ======================================================================
/** // Strings have string like argument traits.
* 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.
*/
template<> template<>
struct ArgTraits<std::string> { struct ArgTraits<std::string> {
typedef StringLike ValueCategory; typedef StringLike ValueCategory;

1
tests/test87.out Normal file
View File

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

12
tests/test87.sh Executable file
View File

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