是否可以在 C++14 中分配和验证 constexpr 结构?
Is it possible to assign and verify a constexpr structure in C++14?
我实现了一个getop()
in C++。这是一个 class 有各种花里胡哨的东西。
其中一个响铃将是一种验证用户在编译时输入有效选项的方法。我已经有一部分用于标志(此处未显示),但我一直在努力使其适用于 struct option
,但目前我没有取得太大成功。
首先,代码允许我使用 define_option()
函数定义一个选项数组。我希望能够以任何顺序指定选项结构的字段,并对它们进行一些健全性检查。所以我使用一个模板函数的参数列表。每个参数都是一个 class,当场实例化,然后 define_option()
为每个字段选择正确的 class,提取值。
到目前为止,一切都很顺利。相当基础的 C++。
我遇到问题的地方是 define_option()
class。比如说我要尝试以下操作:
... define_option(...)
{
...
option opt = { ... };
static_assert(opt.f_short_name != '[=10=]', "this failed");
...
}
这里我得到一个错误。 static_assert()
告诉我 opt
不是常数。
a.cpp:168:1: error: non-constant condition for static assertion
所以下一步我的步骤是将 opt
变量标记为 constexpr
(错误说要解决 static_assert()
。)
... define_option(...)
{
...
constexpr option opt = { ... };
...
}
现在即使没有 static_assert()
,代码也无法编译。我收到以下错误:
a.cpp:168:5: error: ‘args#0’ is not a constant expression
我认为它在 define_option()
函数中并不是真正可行的,尽管可以检查结果选项列表,如下面的工作示例所示。所以最后 opt
全局变量是一个在编译时完全定义的静态变量(不需要代码在运行时重新处理 table )但这对我没有帮助,因为我不能确保每个选项的参数都能按预期工作。
我有 online running sample 大肠杆菌。
// compiled with: g++ -std=c++14 -o a ~/tmp/a.cpp
//
#include <iostream>
typedef char32_t short_name_t;
constexpr short_name_t NO_SHORT_NAME = L'[=12=]';
struct option
{
short_name_t f_short_name = NO_SHORT_NAME;
char const * f_name = nullptr;
};
template<typename T, T default_value>
class OptionValue
{
public:
typedef T value_t;
constexpr OptionValue<T, default_value>()
: f_value(default_value)
{
}
constexpr OptionValue<T, default_value>(T const v)
: f_value(v)
{
}
constexpr value_t get() const
{
return f_value;
}
private:
value_t f_value;
};
class ShortName
: public OptionValue<short_name_t, NO_SHORT_NAME>
{
public:
constexpr ShortName()
: OptionValue<short_name_t, NO_SHORT_NAME>()
{
}
constexpr ShortName(short_name_t name)
: OptionValue<short_name_t, NO_SHORT_NAME>(name)
{
}
};
class Name
: public OptionValue<char const *, nullptr>
{
public:
constexpr Name()
: OptionValue<char const *, nullptr>()
{
}
constexpr Name(char const * name)
: OptionValue<char const *, nullptr>(name)
{
}
};
template<typename T, typename F, class ...ARGS>
constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
{
return first.get();
}
template<typename T, typename F, class ...ARGS>
constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
{
return find_option<T>(args...);
}
template<class ...ARGS>
constexpr option define_option(ARGS ...args)
{
option opt =
{
.f_short_name = find_option<ShortName >(args..., ShortName()),
.f_name = find_option<Name >(args...),
};
return opt;
}
constexpr option const opt[] =
{
define_option(
Name("--help"),
ShortName('h')
)
};
// this test works as expected here
// but it does not work from inside define_option()
//
static_assert(opt[0].f_name[0] != '-', "Wrong start?!");
int main(int argc, char * argv [])
{
std::cerr << "opt[0].f_short_name = " << opt[0].f_short_name << std::endl;
return 0;
}
目前我仅限于 C++14。如果有 C++17 解决方案,我仍然会感兴趣。
只需添加一些可以调用的内容 non-constant。说,抛出异常。
template<class ...ARGS>
constexpr option define_option(ARGS ...args)
{
option opt =
{
.f_short_name = find_option<ShortName >(args..., ShortName()),
.f_name = find_option<Name >(args...),
};
if(/* check fails */) throw something;
return opt;
}
然后当你尝试做
constexpr option const opt[] =
{
define_option(
Name("--help"),
ShortName('h')
)
};
并且检查失败,编译器会抱怨这个对define_option
的调用不是常量表达式,不能用于初始化一个constexpr
变量。
如果在运行时调用此函数,您甚至可以设置 something
以产生链接器错误。参见例如.
我实现了一个getop()
in C++。这是一个 class 有各种花里胡哨的东西。
其中一个响铃将是一种验证用户在编译时输入有效选项的方法。我已经有一部分用于标志(此处未显示),但我一直在努力使其适用于 struct option
,但目前我没有取得太大成功。
首先,代码允许我使用 define_option()
函数定义一个选项数组。我希望能够以任何顺序指定选项结构的字段,并对它们进行一些健全性检查。所以我使用一个模板函数的参数列表。每个参数都是一个 class,当场实例化,然后 define_option()
为每个字段选择正确的 class,提取值。
到目前为止,一切都很顺利。相当基础的 C++。
我遇到问题的地方是 define_option()
class。比如说我要尝试以下操作:
... define_option(...)
{
...
option opt = { ... };
static_assert(opt.f_short_name != '[=10=]', "this failed");
...
}
这里我得到一个错误。 static_assert()
告诉我 opt
不是常数。
a.cpp:168:1: error: non-constant condition for static assertion
所以下一步我的步骤是将 opt
变量标记为 constexpr
(错误说要解决 static_assert()
。)
... define_option(...)
{
...
constexpr option opt = { ... };
...
}
现在即使没有 static_assert()
,代码也无法编译。我收到以下错误:
a.cpp:168:5: error: ‘args#0’ is not a constant expression
我认为它在 define_option()
函数中并不是真正可行的,尽管可以检查结果选项列表,如下面的工作示例所示。所以最后 opt
全局变量是一个在编译时完全定义的静态变量(不需要代码在运行时重新处理 table )但这对我没有帮助,因为我不能确保每个选项的参数都能按预期工作。
我有 online running sample 大肠杆菌。
// compiled with: g++ -std=c++14 -o a ~/tmp/a.cpp
//
#include <iostream>
typedef char32_t short_name_t;
constexpr short_name_t NO_SHORT_NAME = L'[=12=]';
struct option
{
short_name_t f_short_name = NO_SHORT_NAME;
char const * f_name = nullptr;
};
template<typename T, T default_value>
class OptionValue
{
public:
typedef T value_t;
constexpr OptionValue<T, default_value>()
: f_value(default_value)
{
}
constexpr OptionValue<T, default_value>(T const v)
: f_value(v)
{
}
constexpr value_t get() const
{
return f_value;
}
private:
value_t f_value;
};
class ShortName
: public OptionValue<short_name_t, NO_SHORT_NAME>
{
public:
constexpr ShortName()
: OptionValue<short_name_t, NO_SHORT_NAME>()
{
}
constexpr ShortName(short_name_t name)
: OptionValue<short_name_t, NO_SHORT_NAME>(name)
{
}
};
class Name
: public OptionValue<char const *, nullptr>
{
public:
constexpr Name()
: OptionValue<char const *, nullptr>()
{
}
constexpr Name(char const * name)
: OptionValue<char const *, nullptr>(name)
{
}
};
template<typename T, typename F, class ...ARGS>
constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
{
return first.get();
}
template<typename T, typename F, class ...ARGS>
constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_option(F first, ARGS ...args)
{
return find_option<T>(args...);
}
template<class ...ARGS>
constexpr option define_option(ARGS ...args)
{
option opt =
{
.f_short_name = find_option<ShortName >(args..., ShortName()),
.f_name = find_option<Name >(args...),
};
return opt;
}
constexpr option const opt[] =
{
define_option(
Name("--help"),
ShortName('h')
)
};
// this test works as expected here
// but it does not work from inside define_option()
//
static_assert(opt[0].f_name[0] != '-', "Wrong start?!");
int main(int argc, char * argv [])
{
std::cerr << "opt[0].f_short_name = " << opt[0].f_short_name << std::endl;
return 0;
}
目前我仅限于 C++14。如果有 C++17 解决方案,我仍然会感兴趣。
只需添加一些可以调用的内容 non-constant。说,抛出异常。
template<class ...ARGS>
constexpr option define_option(ARGS ...args)
{
option opt =
{
.f_short_name = find_option<ShortName >(args..., ShortName()),
.f_name = find_option<Name >(args...),
};
if(/* check fails */) throw something;
return opt;
}
然后当你尝试做
constexpr option const opt[] =
{
define_option(
Name("--help"),
ShortName('h')
)
};
并且检查失败,编译器会抱怨这个对define_option
的调用不是常量表达式,不能用于初始化一个constexpr
变量。
如果在运行时调用此函数,您甚至可以设置 something
以产生链接器错误。参见例如