Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions example/program_options.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@

// Copyright 2021 Samuel Debionne
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

// g++ -std=c++14 -Iinclude example/program_options.cpp -o example/program_options /usr/lib/libboost_program_options.a

#define _CRT_SECURE_NO_WARNINGS

#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/program_options.hpp>

#include <type_traits>
#include <iostream>

namespace app
{

enum class log_level {
fatal,
error,
warning,
trace
};

BOOST_DESCRIBE_ENUM(log_level, fatal, error, warning, trace)

using boost::describe::operators::operator<<;

// Generic program_options custom validator for (described) enums
template <
typename E,
typename Ed = boost::describe::describe_enumerators<E>,
typename = std::enable_if_t<
std::is_enum<E>::value && !boost::mp11::mp_empty<Ed>::value
>
>
void validate(boost::any& v,
const std::vector<std::string>& values,
E* target_type, int)
{
using namespace boost::program_options;

// Make sure no previous assignment to 'a' was made.
validators::check_first_occurrence(v);
// Extract the first string from 'values'. If there is more than
// one string, it's an error, and exception will be thrown.
const std::string& name = validators::get_single_string(values);

// Convert string to enum
E r = {};
bool found = boost::describe::enum_from_string(name.c_str(), r);

if (found)
v = boost::any(r);
else
throw validation_error(validation_error::invalid_option_value);
}

} //namespace app

int main(int argc, char *argv[])
{
namespace po = boost::program_options;

app::log_level lvl;

// Declare the supported options.
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("log-level", po::value<app::log_level>(&lvl), "set log severity level")
;

try {
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);

if (vm.count("help")) {
std::cout << desc << "\n";
return 1;
}

if (vm.count("log-level")) {
std::cout << "Log level was set to " << lvl << ".\n";
} else {
std::cout << "Log level was not set.\n";
}
}
catch (std::exception& ex)
{
std::cerr << "ERROR: " << ex.what() << std::endl;
}
}
13 changes: 13 additions & 0 deletions include/boost/describe/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/describe/bases.hpp>
#include <boost/describe/members.hpp>
#include <boost/describe/modifiers.hpp>
#include <boost/describe/enumerators.hpp>
#include <boost/mp11/algorithm.hpp>
#include <type_traits>
#include <iosfwd>
Expand Down Expand Up @@ -160,6 +161,18 @@ template<class T, class Ch, class Tr> std::enable_if_t<
return os;
}

template <typename E, class Ch, class Tr> std::enable_if_t<
has_describe_enumerators<E>::value,
std::basic_ostream<Ch, Tr>&>
operator<<( std::basic_ostream<Ch, Tr>& os, E e)
{
boost::mp11::mp_for_each< boost::describe::describe_enumerators<E> >([&](auto D) {
if( e == D.value ) os << D.name;
});

return os;
}

} // namespace operators

} // namespace describe
Expand Down