【发布时间】:2016-09-16 11:52:48
【问题描述】:
这是我的代码的 mcve:(如果重要,Options_proxy 和 Options 有 constexpr ctors)。我知道它仍然远非简单,但在仍然显示错误的同时无法进一步简化它:
template <class Impl>
struct Options_proxy : Impl {
using Flag = typename Impl::Flag;
friend constexpr auto operator!(Flag f) -> Options_proxy {
return {}; // <-- error here
};
};
template <class Impl>
struct Options : Impl {
using Flag = typename Impl::Flag;
};
struct File_options_impl {
enum class Flag : unsigned { nullflag, read, write };
friend constexpr auto operator!(Flag f) -> Options_proxy<File_options_impl>;
};
using File_options = Options<File_options_impl>;
auto foo()
{
!File_options::Flag::write; // <-- required from here
}
gcc 6 和 7 给出这个错误:
In instantiation of 'constexpr Options_proxy<File_options_impl> operator!(Options_proxy<File_options_impl>::Flag)':
required from ... etc etc...
error: return type 'struct Options_proxy<File_options_impl>' is incomplete
clang 编译成功。
如果符合以下条件,则代码符合 gcc:
- 我删除了
operator!的constexpr
或
- 在运算符调用之前添加
Options_proxy<File_options_impl>类型的对象:
像这样:
auto foo()
{
Options_proxy<File_options_impl> o;
!File_options::Flag::write; // <-- now OK in gcc also
}
这是一个 gcc 错误还是代码中的一些未定义行为,例如未指定或不需要诊断?
至于编写此类代码的动机:
我想创建(主要是为了好玩)一个类型安全的标志/选项系统(没有宏):
图书馆黑魔法:
template <class Impl>
requires Options_impl<Impl>
struct Options : Impl {
// go crazy
};
用户代码:
struct File_options_impl {
// create a system where here the code
// needs to be as minimal as possible to avoid repetition and user errors
// this is what the user actually cares about
enum class Flag : unsigned { nullflag = 0, read = 1, write = 2, create = 4};
// would like not to need to write this,
// but can't find a way around it
friend constexpr auto operator!(Flag f1) -> Options_proxy<File_options_impl>;
friend constexpr auto operator+(Flag f1, Flag f2) -> Options_proxy<File_options_impl>;
friend constexpr auto operator+(Flag f1, Options_proxy<File_options_impl> f2) -> Options_proxy<File_options_impl>;
};
using File_options = Options<File_options_impl>;
然后:
auto open(File_options opts);
using F_opt = File_options::Flag;
open(F_opt::write + !F_opt::create);
【问题讨论】:
标签: c++ templates language-lawyer friend incomplete-type