我需要定义一个接受多个 3D 坐标作为参数的 C++ 模板。当这些坐标的所有维度都定义为单独的整数变量时,参数列表将变得非常长 - 3 个坐标需要 9 个参数,这使得模板难以使用。
因此,非常希望以使用编译时数组的方式声明模板。它们的默认参数也应该直接在模板声明的位置声明为值,而不是变量名。
经过一些实验,令我惊讶的是,我发现 GCC 13 将接受以下 C++ 程序std=c++20
:
#include <cstdio>
#include <array>
template <
std::array<int, 3> offset = {0, 0, 0}
>
struct Array
{
void operator() (int i, int j, int k)
{
printf("(%d, %d, %d)\n", i + offset[0], j + offset[1], k + offset[2]);
}
};
int main(void)
{
Array arr_default;
arr_default(0, 0, 0);
Array<{1, 1, 1}> arr;
arr(0, 0, 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然而,clang 18 拒绝使用 …
c++ language-lawyer list-initialization braced-init-list c++-templates
我遇到了一个非常奇怪的 clang 问题。
当我使用 gcc-11 使用 C++20 编译代码时,一切都很好。
当我尝试使用 C++20 和 clang-14 编译它时出现问题(使用 clang-15/16/17 没有帮助)。
链接器抱怨对容器的所有类模板实例化的未定义引用,下面是错误消息之一:
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-ded8d6.o:(.rodata._ZTV6WidgetINSt7__cxx114listIlSaIlEEEE[_ZTV6WidgetINSt7__cxx114listIlSaIlEEEE]+0x10): undefined reference to `Widget<std::__cxx11::list<long, std::allocator<long> > >::doSth()'
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-ded8d6.o:(.rodata._ZTV6WidgetISt6vectorIbSaIbEEE[_ZTV6WidgetISt6vectorIbSaIbEEE]+0x10): undefined reference to `Widget<std::vector<bool, std::allocator<bool> > >::doSth()'
Run Code Online (Sandbox Code Playgroud)
到目前为止,我已经设法通过更改 Widget 的 doSth 签名来解决这个问题
void doSth() override
Run Code Online (Sandbox Code Playgroud)
到:
__attribute__((used)) void doSth() override
Run Code Online (Sandbox Code Playgroud)
但这是——正如我上面所说的——而是一种解决方法,而不是真正的解决方案。有谁知道为什么 Clang 无法处理这个问题?
下面是编译器资源管理器和 C++ 见解的链接以及最小的可重现示例,这些示例是从我的代码库中提取的,并减少到绝对最小值,以便重现该示例并显示我的意图。
编译器浏览器:https://godbolt.org/z/83dMMvozn
C++ 见解:https://cppinsights.io/s/e35151b2
更新
我删除了不需要的代码部分,并添加了另一个(可接受的)解决方法 - 我没有使用 lambda 作为“调用”调用的参数,而是使用了可调用结构 - 它“神奇地”起作用了 - 但是,我不明白为什么它不适用于 lambda。
#include <memory>
#include <type_traits>
#include <variant>
#include <vector>
#include <list>
struct …
Run Code Online (Sandbox Code Playgroud) 我想创建一个具有同步和协程版本的函数,而不使用模板专门化,即使用if constexpr
.
这是我写的函数:
template <Async _a>
AsyncResult<int, _a> func(int a) {
if constexpr (_a == Async::Disable)
return a;
else
co_return a;
}
Run Code Online (Sandbox Code Playgroud)
但是当我实例化真正的分支时,它给出了一个错误
auto a = func<Async::Disable>(1); // compiler error
auto b = func<Async::Enable>(2); // ok
Run Code Online (Sandbox Code Playgroud)
error: unable to find the promise type for this coroutine
Run Code Online (Sandbox Code Playgroud)
为什么这不起作用?
例如
template <class T1, class T2>
class foo
{
T1 t1;
T2 t2;
T1 bar(); //Always exists
decltype(t1(t2)) baz(); //Should only exist if t1(t2) is valid
};
Run Code Online (Sandbox Code Playgroud)
如果baz
无效,我仍然希望程序能够编译,只要没有人真正调用baz
.
考虑如下情况:
template<typename T>
class A { ... };
template<typename T, typename DataType = std::vector<A<T>>>
class B {
....
DataType data;
...
}
Run Code Online (Sandbox Code Playgroud)
在我的例子中DataType
,类型可以是任何std“容器”,但它必须始终专门针对类型A。A的使用对于类B之外应该是透明的,但是在没有默认类型的B的定义中DataType
应该明确指定例如B<int, std::deque<A<int>>
。我想消除这种可能性并实现类似的目标:
template<typename T, typename container = std::vector>
class B{
using DataType = container<A<T>>;
...
}
Run Code Online (Sandbox Code Playgroud)
这样我就可以专注于 B 之类的B<int, std::vector>
。当然它不能完全像这样,因为container
在这种情况下应该是一个完整的类型,然后必须专门化。有没有办法用 c++14 来实现这一点?
我偶然发现了模板的问题,clang++
我不知道如何解决。
我希望使用以类和函数作为参数的模板化函数。但是当函数是重载函数时,我得到的错误candidate template ignored: couldn't infer template argument 'F'
是完全合理的。
例如,示例程序
#include <iostream>
#include <math.h>
template<class T, typename F>
T foo(F f,T x){
return f(x);
}
int main(void) {
std::cout << "foo(sinf,0.34) is " << foo(sinf,0.34) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
完全按照我想要的方式工作。现在,如果我使用重载函数(例如,sin
而不是 )sinf
,则无法推断模板参数。如何更改 的函数模板foo
以帮助编译器解析 的类型F
?
我有一个Optional_monadic 类,它是从 std::Optional 类继承的
template <class T>
class monadic_optional : public std::optional<T>
{
public:
using std::optional<T>::optional;
monadic_optional(T value) : std::optional<T>(value) {}
}
Run Code Online (Sandbox Code Playgroud)
在这堂课中我描述了该方法
template <class Return>
nonstd::monadic_optional<Return> and_then(std::function<nonstd::monadic_optional<Return>(T)> func)
{
if (this->has_value())
return func(this->value());
else
return std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)
我想使用概念将模板传递给检查它是否是函数的方法。我如何使用概念来实现这一点?
template <class T>
concept convertible_to_func = std::convertible_to <T, std::function<nonstd::monadic_optional<Return>(T)>>
requires
{
};
nonstd::monadic_optional<T> and_then(T func)
{
if (this->has_value())
return func(this->value());
else
return std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)
它应该看起来像这样,但它无法编译。
假设我们有一个简单的概念,例如:
template <typename T>
concept MyConcept = requires {
T::value == 42;
};
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这个概念是说,如果代码T::value == 42
对于类型 T 有效,我就会通过。所以value
必须是静态成员,对吗?
我有一个struct
struct Test { int value = 0; }
Run Code Online (Sandbox Code Playgroud)
和下一个模板函数
template <MyConcept T>
void call() { /*...*/ }
Run Code Online (Sandbox Code Playgroud)
当我尝试这样做时:
int main()
{
call<Test>();
}
Run Code Online (Sandbox Code Playgroud)
有用!
问题是:它为什么有效? Test::value == 42
不是该类型的有效代码Test
。
我找到了一种修复它的方法,例如:
template <typename T>
concept MyConcept = requires {
*(&T::value) == 42;
};
Run Code Online (Sandbox Code Playgroud)
它按预期“工作”:
<source>:6:20: note: the required expression '((* & T::value) == 42)' is …
Run Code Online (Sandbox Code Playgroud) 我正在使用 C++20。我能够检查类型是否是某种向量/双端队列/列表,如下所示:
template <typename N> struct is_listish_trait {
static constexpr bool value = 0;
};
/* These are listish specializations */
template <typename N, typename A> struct is_listish_trait<std::vector<N, A>> {
static constexpr bool value = 1;
};
template <typename N, typename A> struct is_listish_trait<std::list<N, A>> {
static constexpr bool value = 1;
};
template <typename N, typename A> struct is_listish_trait<std::deque<N, A>> {
static constexpr bool value = 1;
};
template <typename T>
static constexpr bool is_listish = is_listish_trait<T>::value; …
Run Code Online (Sandbox Code Playgroud) 使用 type_identity 作为尾随返回类型的目的是什么?
https://en.cppreference.com/w/cpp/types/add_reference提供了以下可能的 add_lvalue_reference 和 add_rvalue_reference 实现
namespace detail {
template <class T>
struct type_identity { using type = T; }; // or use std::type_identity (since C++20)
template <class T> // Note that `cv void&` is a substitution failure
auto try_add_lvalue_reference(int) -> type_identity<T&>;
template <class T> // Handle T = cv void case
auto try_add_lvalue_reference(...) -> type_identity<T>;
template <class T>
auto try_add_rvalue_reference(int) -> type_identity<T&&>;
template <class T>
auto try_add_rvalue_reference(...) -> type_identity<T>;
} // namespace detail
template <class T> …
Run Code Online (Sandbox Code Playgroud) 有很多类似的问题,但我找不到这个问题:给定
template <typename T>
struct S {
int f(int x) const { return x; }
};
Run Code Online (Sandbox Code Playgroud)
我希望能够f
根据T
. 显而易见的事情不起作用:
#include <type_traits>
template <typename T>
struct MyProperty { static constexpr auto value = std::is_same_v<T, float>; };
template <typename T>
struct S {
template <typename = std::enable_if_t<MyProperty<T>::value>>
int f(int x) const { return x; }
};
int main() {
S<int> s;
}
Run Code Online (Sandbox Code Playgroud)
我能想到的最接近的是一个假人typename U = T
:
template <typename U = T, typename = std::enable_if_t<MyProperty<U>::value>>
int f(int x) …
Run Code Online (Sandbox Code Playgroud) 我的用例如下:
template <typename T>
struct peel {
using type = std::conditional_t<std::is_pointer_v<T>, typename peel<std::remove_pointer_t<T>>::type, T>;
};
template <typename T>
using peel_t = typename peel<T>::type;
Run Code Online (Sandbox Code Playgroud)
但是,如果您调用此方法,peel_t<int *>
则会返回错误:
错误:“peel<int>”中没有名为“type”的类型
问题似乎是缺乏终止条件,因为peel
没有专门处理没有更多指针需要删除的情况。但我脑子里std::conditional_t
应该已经在处理这个问题了。
我的问题是,有没有一种方法可以std::conditional_t
在需要递归的场景中工作(比如这个)?我特别希望通过以下检查:
static_assert(std::is_same_v<peel_t<int **>, int>);
Run Code Online (Sandbox Code Playgroud) 假设我有一个结构体 X,我想根据某些条件填写所有字段。我想区分要传递给函数的参数,并根据提供的参数创建然后返回该对象。我很好奇是否应该在 C++ 中使用可变参数模板?伪代码。
#include <iostream>
using namespace std;
struct X
{
string a;
string b;
string c;
}
X generateTransaction(const string& e, const string& f, const string& g)
{
X one;
if (e)
one.a = e;
if (f)
one.b = f;
if (g)
one.c = g;
return one;
}
int main()
{
generateTransaction(e = "first");
generateTransaction(e = "abc", f = "second");
generateTransaction(g = "third");
generateTransaction(e = "test", g = "third");
generateTransaction("m", "n", "o");
return 0;
}
Run Code Online (Sandbox Code Playgroud) c++ ×13
c++-templates ×13
c++20 ×5
templates ×3
type-traits ×3
c++-concepts ×2
clang ×2
c++11 ×1
c++17 ×1
clang++ ×1
sfinae ×1
std ×1