小编W.F*_*.F.的帖子

为什么clang无法使用默认的integer_sequence实例化嵌套的可变参数模板?

考虑一个例子:

#include <utility>

template <class... Ts>
struct pack { 
   static constexpr std::size_t size = sizeof...(Ts);
};

template <class P, class = std::make_index_sequence<P::size>>
struct ipack;

template <class... Ts, std::size_t... Is>
struct ipack<pack<Ts...>, std::index_sequence<Is...>> { 
   static constexpr std::size_t size = sizeof...(Ts);
};

template <class IP, class = std::make_index_sequence<IP::size>>
struct vpack;

template <class... Ts, std::size_t... Is>
struct vpack<ipack<pack<Ts...>>, std::index_sequence<Is...>> { 
   static constexpr std::size_t size = sizeof...(Ts);
};

int main() {
    vpack<ipack<pack<int, int, int>>> vp;
    static_cast<void>(vp);
}
Run Code Online (Sandbox Code Playgroud)

clang 报告问题:

prog.cc:29:39: error: implicit instantiation …
Run Code Online (Sandbox Code Playgroud)

c++ templates c++14

11
推荐指数
1
解决办法
383
查看次数

在decltype(auto)的情况下,lambda是否有特殊规则?

如果我正确理解了这个答案并引用了标准部分[dcl.type.auto.deduct-5],那么代码如下:

decltype(auto) a = e;
Run Code Online (Sandbox Code Playgroud)

总是相当于

decltype( e  ) a = e;
Run Code Online (Sandbox Code Playgroud)

但是现在问题出现了,而不是e我把lambda表达式放到decltype(auto):

decltype(auto) lambda = [](){};
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,这在gccclang中成功编译.我所经历的冲击的原因在于标准,其中特别指出lambda不应出现在未评估的操作数中[expr.prim.lambda#2](强调我的):

lambda-expression是一个prvalue,其结果对象称为闭包对象.lambda表达式不应出现在未评估的操作数,模板参数,别名声明,typedef声明或函数体和默认参数之外的函数或函数模板的声明中.

但正如我所提到的,这个例子相当于:

decltype([](){}) lambda = [](){};
Run Code Online (Sandbox Code Playgroud)

明确写出的上述代码显然是不正确的.当然,我们可以假设[](){}里面的语句decltype是一种引用,实际上并不是像结构化绑定那样的引用,但是标准中有一条特殊的规则,我错过了覆盖lambda的初始化decltype(auto)

c++ lambda decltype language-lawyer c++14

11
推荐指数
1
解决办法
421
查看次数

为什么直接列表初始化会导致类型引用转换的歧义,如果声明了对类型的引用运算符和对类型的引用?

这个答案的背景下,问题就出现了.

考虑一个例子:

struct foo {
    int value;
    operator int&(){ return value; }
    operator int(){ return value; }
};

int main () {
    int &a(foo{}); // #1
    //int &b{foo{}}; // #2 -- ambiguity
    int &c = foo{}; // #3
    //int &d = {foo{}}; // #4-- ambiguity
    int &d { a }; // #5
    int &e = { a }; // #6
    (void)a;
    (void)c;
    (void)d;
    (void)e;
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么#2和#4引起歧义,而#1和#3则不然.所以问题是 - 为什么直接列表初始化会导致隐式强制转换引用的歧义,如果声明类型和对类型的引用的转换运算符?

c++ ambiguity typecast-operator list-initialization

10
推荐指数
1
解决办法
128
查看次数

为什么允许一些非常量表达式作为constexpr逗号运算符的操作数?

考虑一个简单的例子:

int foo() {
    return 3;
}

template <int>
struct Bar {};

int a;

int main() {
    int b;
    //Bar<((void)foo(), 1)> bar1;  //case 1. compilation error as expected
    Bar<((void)a, 2)> bar2;        //case 2. no error (long shot but `a' has a linkage so maybe expected)
    Bar<((void)b, 3)> bar3;        //case 3. no error ? (`b' does not have linkage) 
    (void)bar2;
    (void)bar3;
}
Run Code Online (Sandbox Code Playgroud)

我会说这是一个错误,但最新的[clang][gcc]接受代码所以也许我错过了一些使代码有效的相关标准规则?

c++ comma-operator language-lawyer constexpr c++11

10
推荐指数
1
解决办法
263
查看次数

std ::如何在没有显式std :: forward的情况下应用转发参数?

考虑可能的实施std::apply:

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence<I...>) 
{
    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}
}  // namespace detail

template <class F, class Tuple>
constexpr decltype(auto) apply(F &&f, Tuple &&t) 
{
    return detail::apply_impl(
        std::forward<F>(f), std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{});
}
Run Code Online (Sandbox Code Playgroud)

为什么在调用f带有参数元组的function()来传递(t)时,我们不需要在实现std::forward中对元组的每个元素std::get<I>(std::forward<Tuple>(t))...执行?

c++ perfect-forwarding c++17 stdapply

9
推荐指数
1
解决办法
342
查看次数

在模板模板参数的情况下,decltype(auto)可转发的参考非类型模板参数是否可转发

又一个decltype(auto)模板模板参数问题.这次我能够创建的最小代码重现错误如下所示:

template <template <decltype(auto)> class TT, decltype(auto) V>
void foo(TT<V>) {
};

template <decltype(auto)>
struct Bar{};

int x;

int main() {
    foo(Bar<(x)>{});
}
Run Code Online (Sandbox Code Playgroud)

这在[clang]中导致:

prog.cc:11:5: error: no matching function for call to 'foo'
    foo(Bar<(x)>{});
    ^~~
prog.cc:2:6: note: candidate template ignored: substitution failure [with TT = Bar]: non-type template argument is not a constant expression
void foo(TT<V>) {
     ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

[gcc]接受代码.

根据我的理解,代码格式正确,并且clang在解释方面存在错误,但在向lvvm提交错误之前需要确认.我对吗?

c++ templates template-templates language-lawyer c++17

9
推荐指数
1
解决办法
162
查看次数

在什么基础上,将由单个元素组成的参数包的表达式转换为未表示的表达式

考虑一个例子:

#include <type_traits>

template <class... Ts>
decltype (auto) foo(Ts... ts) {
      return (ts->x + ...);
}

struct X {
    int x;
};

int main() {
    X x1{1};
    static_assert(std::is_reference_v<decltype(foo(&x1))>);
}
Run Code Online (Sandbox Code Playgroud)

[现场演示]

decltype(auto)从带括号的左值推导出的,应根据[cl.type.simple] /4.4推导出左值参考.例如:

decltype(auto) foo(X *x) { // type of result == int&
    return (x->x);
}
Run Code Online (Sandbox Code Playgroud)

但是snipped会触发static_assert.即使我们将表达式组合成额外的括号,例如:

return ((ts->x + ...));
Run Code Online (Sandbox Code Playgroud)

它不会改变效果.

标准中是否有一点可以防止将单个元素的折叠表达式推导到左值参考中?


编辑

作为Johannes Schaub的一个重点- litb clang实际上确实将代码双parens版本解释为带括号的左值并推导出左值引用.在这种情况下,我会将其解释为gcc错误.然而,具有单parens版本的版本仍然存在问题.让我感到困惑的是,至少在多个元素的情况下,必须将版本转换为带括号的代码 - 以实现运算符优先级.例如:

(x + ...)*4 -> (x1 + x2)*4
Run Code Online (Sandbox Code Playgroud)

不一致的原因是什么?

c++ decltype language-lawyer fold-expression c++17

9
推荐指数
1
解决办法
656
查看次数

可以使用自动占位符在非类型模板参数中推导出函数结果吗?

考虑简单的例子:

template <auto(*X)()>
struct Foo {
    decltype(X()) x;
};

int bar();

int main() {
    static_cast<void>(Foo<bar>{});
}
Run Code Online (Sandbox Code Playgroud)

无论[GCC][铛]似乎接受的代码.代码真的符合c ++ 17吗?如果是这样,还有其他一些规则会使下面的代码生成错误吗?

template <class T, auto(*X)(T)>
struct Foo {
    decltype(X(0)) x;
};

int bar(int);

int main() {
    static_cast<void>(Foo<int, bar>{});
}
Run Code Online (Sandbox Code Playgroud)

这个只让[gcc]不高兴.

错误信息:

prog.cc: In function 'int main()':
prog.cc:9:35: error: unable to deduce 'auto (*)(T)' from 'bar'
     static_cast<void>(Foo<int, bar>{});
                                   ^
prog.cc:9:35: note:   mismatched types 'T' and 'int'
Run Code Online (Sandbox Code Playgroud)

c++ templates language-lawyer c++17

9
推荐指数
1
解决办法
182
查看次数

是默认模板模板参数值推导上下文?

我真的很惊讶gcc和clang都接受这个代码:

#include <iostream>
#include <vector>
#include <type_traits>

template <class T, template <class, class = T> class TT, class Y>
T foo(TT<Y>) {
}

int main() {
    static_assert(std::is_same<decltype(foo(std::vector<int>{})), std::allocator<int>>::value);
}
Run Code Online (Sandbox Code Playgroud)

gcc和clang是正确的,默认模板模板参数的值是推导上下文还是编译器扩展?

c++ templates template-templates

8
推荐指数
1
解决办法
142
查看次数

在类的范围内传递指向constexpr函数的指针时,是否滥用推断父模板的参数

我得到的最小例子有点复杂:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static Other<A{} * ptr<Kid>{}> o;
};

int main() {
    Kid<2>{};
}
Run Code Online (Sandbox Code Playgroud)

[GCC]编译代码而没有任何问题,[铛]抱怨匹配Parent针对Kid问题:

prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid'
constexpr int operator*(A, Parent<N>*) { return N; } …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer incomplete-type constexpr template-argument-deduction

8
推荐指数
1
解决办法
226
查看次数