Reputation: 1180
I am trying to write a template like this.
template <char c,typename Options,
basic_string<class,class,class> Options::* member>
struct option_string;
However I keep getting a compilation error.
I would like to know how to write a template that takes three options: a char
, any class and a pointer to a member of that class which must be a basic_string
specialization.
I want to avoid writing a template for each specialization of basic_string
.
My goal is to created a generic command line option library. The following is how I would like to use it.
class Options : public Command_Line_Options_Parser<Options> {
public:
int integer = 0;
float real_number = 0.0;
bool boolean = false;
bool make_true = false;
bool make_false = true;
std::string string;
typedef Options O;
typedef Command_Line_Options<
option_int<'i',&O::integer>,
option_float<'f',&O::real_number>,
option_bool<'b',&O::boolean>,
option_true<'t',&O::make_true>,
option_false<'t',&O::make_true>,
option_string<'s',&O::string>
>
option_list;
};
int main(int argc,char**argv ) {
Options options;
options.parse(argc,argv);
std::cout << "integer : " << options.integer <<endl;
std::cout << "real_number : " << options.real_number <<endl;
std::cout << "boolean : " << options.boolean <<endl;
std::cout << "make_true : " << options.make_true <<endl;
std::cout << "make_false : " << options.make_false <<endl;
std::cout << "string : " << options.string <<endl;
};
I would prefer for option_string
to accept all specializations of basic_string
instead of just std::string
.
Upvotes: 2
Views: 850
Reputation: 131799
You won't get around having to specify the return type directly. And in that case, why bother with the basic_string
class directly? Just take a typename String
and be done:
template<char C, class Options, class String, String Options::* Member>
struct option_string;
And if you still want to make sure that String
is indeed a specialization of basic_string
, well, take this little helper and static_assert
it:
#include <type_traits>
#include <string>
template<class T>
struct is_basic_string : std::false_type{};
template<class Ch, class Tr, class Al>
struct is_basic_string<std::basic_string<Ch,Tr,Al>> : std::true_type{};
// in 'option_string'
static_assert(is_basic_string<String>::value,
"Data member must be a 'basic_string' specialization.");
Since there doesn't seem to be a need to pass the member pointer as a template argument, I suggest just passing it in the constructor:
template<char C, class Option, class String>
struct option_string{
static_assert(is_basic_string<String>::value,
"Data member must be a 'basic_string' specialization.");
typedef String Option::*member_type;
option_string(member_type m, ...) : member(m), ... { ... }
private:
member_type member;
};
template<char C, class Option, class String>
option_string<C, Option, String> make_option_string(String Option::*member, ...){
return {member, ...};
}
// in code:
auto os = make_option_string<'H'>(&some_type::a_string_member);
Upvotes: 6