我试图实现一个涉及模板的用户定义类型转换的小例子.
#include <cassert>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <type_traits>
template <typename T>
concept bool UIntegral = requires() {
std::is_integral_v<T> && !std::is_signed_v<T>;
};
class Number
{
public:
Number(uint32_t number): _number(number)
{
if (number == 1) {
number = 0;
}
for (; number > 1; number /= 10);
if (number == 0) {
throw std::logic_error("scale must be a factor of 10");
}
}
template <UIntegral T>
operator T() const
{
return static_cast<T>(this->_number);
}
private:
uint32_t _number;
};
void changeScale(uint32_t& …Run Code Online (Sandbox Code Playgroud) 当我尝试这个例子时:
template <typename T>
concept only_int = std::same_as<T, int>;
int add_ints(only_int auto&&... args) {
return (std::forward<decltype(args)>(args) + ... + 0);
}
Run Code Online (Sandbox Code Playgroud)
它有效......但是当我只像这样声明它时:
template <typename T>
concept only_int;
...
// defined later on...
Run Code Online (Sandbox Code Playgroud)
它会抛出编译错误。
这是缺少的功能吗?还是打算就这样离开?
如何测试概念模板参数中是否存在成员类型,即 for typename Container、 test for Container::reverse_iterator?正确的要求子句是什么?
std::common_type<T1, ..., TN>T1是 C++ 中的一个辅助模板,它可以找到所有...TN都可以隐式转换为的通用类型。
根据 C++ 规范,如果某些条件适用,用户可以专门化std::common_type<T1,T2>,并且:
std::common_type<T1, T2>::type并且std::common_type<T2, T1>::type必须表示相同的类型。
然而,common_type<T1, T2>对于用户类型来说,可能是一个非常复杂的专业化,T1并且T2:
namespace std {
template <typename T1, complicated_constraint_of<T1> T2, ...>
struct common_type<complicated_expression_of<T1, ...>, complicated_expression_of<T2, ...>> {
using type = complicated_type_expression_of<T1,T2>;
};
}
Run Code Online (Sandbox Code Playgroud)
一般来说,约束表达式不一定是对称的(例如,我们可以指定 是T2的底T1)。这意味着为了保持对称性,我们需要用T1和T2反转来重写整个特化,但在不犯任何错误的情况下做到这一点是极其困难和脆弱的。
如何common_type<T1,T2>为我自己的类型稳健地定义 的交换特化?
根据草案:
如果给定相同的输入,表达式会产生相同的输出,则该表达式是保持相等的。[ ... ]
和
[...]稳定:具有相同输入对象的此类表达式的两次评估需要具有相同的输出,而无需对这些输入对象进行任何显式干预修改。[...]
强调我的。
这些有什么区别?
什么时候一个表达式可以保持相等但不稳定,反之亦然?
我刚开始做概念。检查表达式的语法非常有用,它为我删除了很多 sfinae 的样板文件。但是我想知道如何检查表达式是否可以在 constexpr 上下文中使用。有时这些表达式会导致无效。我可以想象的方式看起来像这样,没有注释 constexpr 关键字:
template<typename T>
concept foo = requires(T t) {
/* constexpr */ { t.bar(); } -> std::same_as<void>;
/* constepxr */ { T::foo; };
}
Run Code Online (Sandbox Code Playgroud)
但是,我非常怀疑这是正确的语法。有没有一种简单的方法来检查概念中表达式的constexpr-ness?
我不想检查 constexpr 函数的计算对于 的所有可能值是否不会失败t,我想知道我是否可以将该表达式放在编译器期望某些东西在编译时可评估的地方。
以下代码尝试使用概念对类进行部分特化,并向特化添加方法,但被 clang 11.0.0 拒绝:
#include <concepts>
template <typename T> // note: previous template declaration is here
struct S {};
template <std::integral T>
struct S<T>
{
void f();
};
template <std::integral T> // error: type constraint differs in template redeclaration
void S<T>::f()
{
}
Run Code Online (Sandbox Code Playgroud)
clang 给出了错误信息:
<source>:14:16: error: type constraint differs in template redeclaration
template <std::integral T>
^
<source>:3:11: note: previous template declaration is here
template <typename T>
Run Code Online (Sandbox Code Playgroud)
(参见https://godbolt.org/z/Wv1ojK)。为什么这段代码是错误的?或者这是clang中的一个错误?(FWIW,此代码被 gcc trunk 和 MSVC 19.28 接受,尽管这不能保证正确性。)
这段代码:
#include <concepts>
#include <string>
#include <variant>
struct any_callable {
public:
template<typename T>
void operator()(T&&) {}
};
template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };
int main() {
constexpr bool wrapped = is_variant<std::string>;
}
Run Code Online (Sandbox Code Playgroud)
不能在 gcc 11 下编译。它给出了一堆关于valueless_by_exception诸如此类的错误。但是,它确实在 msvc ( Godbolt )下编译。现在,据我所知,在这种情况下,如果它通常无法编译,它将衰减为 false,否则为 true。msvc 的行为似乎支持这一点。
所以:这是 gcc 中的错误,msvc 的非标准功能,和/或我的代码有错吗?
有了概念,C++20提供了很好的语法,比如
template<typename T>
concept SomeConcept = true; // stuff here
template<typename T>
requires SomeConcept<T>
class Foo;
template<SomeConcept T>
class Foo;
Run Code Online (Sandbox Code Playgroud)
其中限制类的两种概念方式是等效的,但后者更简洁。
如果我现在有一些模板模板概念,例如
template<template<typename> typename T>
concept SomeOtherConcept = true; // stuff here
template<template<typename> typename T>
requires SomeOtherConcept<T>
class Foo;
Run Code Online (Sandbox Code Playgroud)
我不知道没有要求子句的非详细(简洁/简短)语法,例如
template<template<typename> SomeotherConcept T>
class Foo;
template<template<SomeOtherConcept> typename T>
class Foo;
Run Code Online (Sandbox Code Playgroud)
没有用,所以
声明这样一个模板模板类的正确语法是什么,对模板模板参数有概念限制?
C++20 允许程序为模板模板参数指定概念。例如,
#include <concepts>
template <typename T> concept Char = std::same_as<T, char>;
template <typename> struct S {};
template <template <Char U> typename T, typename U> T<U> foo() { return {}; }
int main() { foo<S, int>(); }
Run Code Online (Sandbox Code Playgroud)
函数的第一个模板参数foo应该是一个单参数模板。
该概念Char仅被定义为 true 类型char,因此尝试满足它 forint将失败。以上程序被所有编译器接受:https : //gcc.godbolt.org/z/PaeETh6GP
能否请您解释一下,为什么可以指定模板模板参数中的概念,但仍然会被忽略?