我正在研究C++的概念,遇到了一个有趣的问题。我有以下两个自定义的概念:
template<typename T>
concept is_dereferencable = requires (T t) { *t; };
template<typename T>
concept is_printable = requires (T t) { std::cout << t; };
顾名思义,第一个函数用于确定给定的类型是否可以解引用,而另一个函数用于检查类型是否支持输出操作符。我还有一个函数模板,名为println
,如下所示:
template<typename T>
void println(const T& t)
{
if constexpr (is_dereferencable<T>) {
if constexpr (is_printable<decltype(*t)>) {
std::cout << *t << '\n';
}
} else if constexpr (is_printable<T>) {
std::cout << t << '\n';
}
}
当且仅当类型T
是可解引用的,并且解引用的值的类型是可打印的时,这个函数才会打印解引用的值*t
,所以,举个例子,我可以使用这个函数模板,其中包含一个std::optional:
int main
{
std::optional<std::string> stringOpt {"My Optional String"};
::println(stringOpt);
return 0;
}
这将按预期打印My Optional String
。虽然这很好,但如果dereferenceable的解引用值的类型不可打印,则函数将不打印任何内容。因此,对于用户定义类型Person
,以下代码将不打印任何内容:
struct Person
{
std::string m_name;
explicit Person(const std::string& name) : m_name {name} {}
};
int main
{
std::optional<Person> personOpt {"John Doe"}
::println(personOpt);
return 0;
}
所以我想把上面的编译时if
s移到一个requires
子句中,以便在这种情况下得到编译时错误。有没有办法做到这一点?有没有办法得到一个给定模板类型T
的解引用类型?为了让它更清楚一点,我想有这样的东西:
template<typename T>
requires is_dereferencable<T> && is_printable<decltype(*T)>
void printDereferencable(const T& t)
{
std::cout << *t << '\n';
}
**P.S.:**我知道我可以删除嵌套的if
,并且在不支持它的地方调用输出操作符时失败。但是,我想特别地将这个编译时错误移到概念中,以获得更清晰的错误消息。
2条答案
按热度按时间kqlmhetl1#
另一个选择是将约束放在参数之后,因此它可以访问它们。
注:应在
const T&
上测试,而不是在T
上测试8xiog9wr2#
您可以使用
std::declval
或者你可以写一个
is_dereference_printable
的概念