是否可以重新声明 C++20 概念?
Can C++20 concepts be redeclared or not?
这个比较简单:根据cppreference article,概念可以重新声明没问题:
所以我想好吧,酷,我不必担心重新声明我创建“可打印枚举”的概念;我可以在我的日志 header 和我的常用类型 header 中声明这个概念,所以我只需要包含需要的内容:
// common types header
#include <enum_traits.hpp>
template<typename E>
concept PrintableEnum = requires(E& e) { {enum_traits<E>::toString(e)} -> std::same_as<const char*>; };
template<PrintableEnum T>
std::ostream& operator<<(std::ostream& os, const T& o)
{
os << enum_traits<T>::toString(o);
return os;
}
// logging header
template<typename T>
concept PrintableEnum = requires(T& e) { {enum_traits<T>::toString(e)} -> std::same_as<const char*>; };
template<PrintableEnum T>
plog::Record& operator<<(plog::Record& rec, const T& o)
{
rec << enum_traits<T>::toString(o);
return rec;
}
(忽略 ostream 过载可能暂时覆盖 plog 记录过载;这可能是我要解决该问题的方法,但我首先对此感到好奇。)
因此,当我尝试编译它时,MSVC 会为每个包含 header 的文件都匹配(它指向哪个文件,因为错误会根据包含顺序发生变化):
[build] commontypes.hpp(25): error C7571: 'PrintableEnum': variable template has already been initialized
[build] logging.hpp(162): note: see declaration of 'PrintableEnum'
另请注意,执行 cppreference 在该屏幕截图中执行的操作并在其中一个文件中的第一个声明的正下方复制 PrintableEnum 声明是相同的问题。
所以这里的cppreference错了?该标准实际上没有说明任何关于重新声明的内容吗? (如果不是在 cppreference 上,我实际上不确定官方 C++ 标准保存在哪里...)我是否需要像 C++ 中的其他任何东西一样担心概念的重新定义?
或者这里MSVC错了? (并不是说我可以对 MSVC 做很多事情...)搜索错误消息只会让我得到有关其他重新声明的信息,例如 类 和变量。显然“概念”不是很SEO-friendly.
This one's rather straightforward: according to the cppreference article, concepts can be redeclared no problem:
不,它没有这么说。此代码段:
template<Incrementable T>
void f(T) requires Decrementable<T>;
template<Incrementable T>
void f(T) requires Decrementable<T>; // OK, redeclaration
不重新声明概念。它甚至没有声明一个概念。它显示的是两次声明相同的 函数模板 。该函数模板受到约束(Incrementable
和 Decrementable
),但它仍然是一个函数模板。
您不能重新声明一个概念。
一个原因是您不能只声明一个概念,您总是还要定义它。你不能只写:
template <class T> concept C;
你可以这样写:
template <class T> void f();
f
这里只是一个函数模板的声明,我可以添加另一个声明。但只有一个定义。这是 ill-formed:
template <class T> void f() { }
template <class T> void f() { }
与 ill-formed:
的方式相同
template <class T> concept C = true;
template <class T> concept C = true;
只能有一个定义。
这个比较简单:根据cppreference article,概念可以重新声明没问题:
所以我想好吧,酷,我不必担心重新声明我创建“可打印枚举”的概念;我可以在我的日志 header 和我的常用类型 header 中声明这个概念,所以我只需要包含需要的内容:
// common types header
#include <enum_traits.hpp>
template<typename E>
concept PrintableEnum = requires(E& e) { {enum_traits<E>::toString(e)} -> std::same_as<const char*>; };
template<PrintableEnum T>
std::ostream& operator<<(std::ostream& os, const T& o)
{
os << enum_traits<T>::toString(o);
return os;
}
// logging header
template<typename T>
concept PrintableEnum = requires(T& e) { {enum_traits<T>::toString(e)} -> std::same_as<const char*>; };
template<PrintableEnum T>
plog::Record& operator<<(plog::Record& rec, const T& o)
{
rec << enum_traits<T>::toString(o);
return rec;
}
(忽略 ostream 过载可能暂时覆盖 plog 记录过载;这可能是我要解决该问题的方法,但我首先对此感到好奇。)
因此,当我尝试编译它时,MSVC 会为每个包含 header 的文件都匹配(它指向哪个文件,因为错误会根据包含顺序发生变化):
[build] commontypes.hpp(25): error C7571: 'PrintableEnum': variable template has already been initialized
[build] logging.hpp(162): note: see declaration of 'PrintableEnum'
另请注意,执行 cppreference 在该屏幕截图中执行的操作并在其中一个文件中的第一个声明的正下方复制 PrintableEnum 声明是相同的问题。
所以这里的cppreference错了?该标准实际上没有说明任何关于重新声明的内容吗? (如果不是在 cppreference 上,我实际上不确定官方 C++ 标准保存在哪里...)我是否需要像 C++ 中的其他任何东西一样担心概念的重新定义?
或者这里MSVC错了? (并不是说我可以对 MSVC 做很多事情...)搜索错误消息只会让我得到有关其他重新声明的信息,例如 类 和变量。显然“概念”不是很SEO-friendly.
This one's rather straightforward: according to the cppreference article, concepts can be redeclared no problem:
不,它没有这么说。此代码段:
template<Incrementable T>
void f(T) requires Decrementable<T>;
template<Incrementable T>
void f(T) requires Decrementable<T>; // OK, redeclaration
不重新声明概念。它甚至没有声明一个概念。它显示的是两次声明相同的 函数模板 。该函数模板受到约束(Incrementable
和 Decrementable
),但它仍然是一个函数模板。
您不能重新声明一个概念。
一个原因是您不能只声明一个概念,您总是还要定义它。你不能只写:
template <class T> concept C;
你可以这样写:
template <class T> void f();
f
这里只是一个函数模板的声明,我可以添加另一个声明。但只有一个定义。这是 ill-formed:
template <class T> void f() { }
template <class T> void f() { }
与 ill-formed:
的方式相同template <class T> concept C = true;
template <class T> concept C = true;
只能有一个定义。