compile error when structopt is used in namespace
chybz opened this issue · 2 comments
chybz commented
Hello and first of all, thanks for this nice piece of software !
When STRUCTOPT(...)
is used inside a namespace, I encounter the following error:
/home/chybz/dev/zap/build/root/include/structopt/third_party/visit_struct/visit_struct.hpp:839:22: error: ‘visitable’ is not a class template
839 | template <> struct visitable<STRUCT_NAME, void> { \
| ^~~~~~~~~
/home/chybz/dev/zap/build/root/include/structopt/app.hpp:13:19: note: in expansion of macro ‘VISITABLE_STRUCT’
13 | #define STRUCTOPT VISITABLE_STRUCT
| ^~~~~~~~~~~~~~~~
so.cpp:16:1: note: in expansion of macro ‘STRUCTOPT’
16 | STRUCTOPT(Options, config_file, bind_address, verbose, user, files);
| ^~~~~~~~~
/home/chybz/dev/zap/build/root/include/structopt/third_party/visit_struct/visit_struct.hpp:839:51: error: explicit specialization of non-template ‘foo::visit_struct::traits::visitable’
839 | template <> struct visitable<STRUCT_NAME, void> {
Here's the minimal example I used, compiled with gcc (Debian 10.2.1-6) 10.2.1 20210110
:
g++ -Wall -std=c++20 -o test test.cpp
#include <iostream>
#include <optional>
#include <vector>
#include <structopt/app.hpp>
namespace foo {
struct Options {
std::string config_file;
std::optional<std::string> bind_address;
std::optional<bool> verbose = false;
std::optional<std::pair<std::string, std::string>> user;
std::vector<std::string> files;
};
STRUCTOPT(Options, config_file, bind_address, verbose, user, files);
}
int main(int argc, char *argv[]) {
try {
auto options = structopt::app("my_app").parse<foo::Options>(argc, argv);
std::cout << "config_file = " << options.config_file << "\n";
} catch (structopt::exception& e) {
std::cout << e.what() << "\n";
std::cout << e.help();
}
}
If I remove namespace foo { ... }
, it compiles without error.
Could you please have a look ?
Thank you !
p-ranav commented
Move the STRUCTOPT
macro usage outside the namespace and it'll work.
structopt
uses visit_struct which has a limitation:
Note: The macro VISITABLE_STRUCT must be used at filescope, an error will occur if it is used within a namespace. You can simply include the namespaces as part of the type, e.g.
#include <iostream>
#include <optional>
#include <vector>
#include <structopt/app.hpp>
namespace foo {
struct Options {
std::string config_file;
std::optional<std::string> bind_address;
std::optional<bool> verbose = false;
std::optional<std::pair<std::string, std::string>> user;
std::vector<std::string> files;
};
}
STRUCTOPT(foo::Options, config_file, bind_address, verbose, user, files);
int main(int argc, char *argv[]) {
try {
auto options = structopt::app("my_app").parse<foo::Options>(argc, argv);
std::cout << "config_file = " << options.config_file << "\n";
} catch (structopt::exception& e) {
std::cout << e.what() << "\n";
std::cout << e.help();
}
}
The above compiles fine.
$ g++ -I. -std=c++17 -o main main.cpp
$ ./main -h
USAGE: my_app [FLAGS] [OPTIONS] config_file files
FLAGS:
-v, --verbose
OPTIONS:
-b, --bind-address <bind_address>
-u, --user <user>
-h, --help <help>
-v, --version <version>
ARGS:
config_file
files
chybz commented
Ok. Thanks for you help !