我发现gcc和clang允许decltype(auto)
在非类型模板参数类型子句中使用.例如:
template <decltype(auto)>
struct X {};
int foo ;
int main() {
X<(foo)> x;
static_cast<void>(x);
}
Run Code Online (Sandbox Code Playgroud)
它是标准兼容功能还是一些gnu扩展?
据我所知 - 泛型lambda被转换为具有模板化的局部范围结构的对象operator()
.这使得通用lambda非常强大且易于使用的工具.另一方面,可以创建嵌套到函数中的结构,但是当结构具有模板化成员时,例如:
#include <iostream>
int main() {
struct inner {
template <class T>
void operator()(T &&i) { }
};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
或者自己模仿:
int main() {
template <class T>
struct inner {
void operator()(T &&i) { }
};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器似乎有编译它的问题:
Run Code Online (Sandbox Code Playgroud)error: invalid declaration of member template in local class
和
Run Code Online (Sandbox Code Playgroud)error: a template declaration cannot appear at block scope
我认为问题在c ++标准中比在编译器bug中更多.lambdas被允许拥有模板化成员而不是本地结构的原因是什么?
我发现了这个问题,但我认为答案有点过时(即使对于c ++ 11,我也不认为这是真的).
考虑一个例子:
#include <iostream>
#include <type_traits>
#include <tuple>
int main() {
auto tup = std::make_tuple(1, 2);
auto [ a, b ] = tup;
decltype(auto) e = a;
std::cout << std::boolalpha << std::is_reference_v<decltype(e)> << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在这个简单的例子中,clang(输出:)false
和gcc(输出:)true
不一致.记住,例如这个Q&As应该e
是一个参考还是一个gcc bug?或者代码可能不正确?
我设法重现问题的最简单的片段如下:
#include <variant>
template <auto V>
using ic = std::integral_constant<decltype(V), V>;
enum { shake };
int milk(ic<shake>);
template <class...>
struct context {
template <auto V>
decltype(milk(ic<V>{})) get() {
return std::get<decltype(milk(ic<V>{}))>(value);
}
std::variant<int> value;
};
int main(){
context<int> c;
c.get<shake>();
}
Run Code Online (Sandbox Code Playgroud)
[clang]中有一些可疑的东西,因为它表明:
prog.cc:13:42: error: a non-type template parameter cannot have type 'auto'
return std::get<decltype(milk(ic<V>{}))>(value);
^
prog.cc:3:16: note: template parameter is declared here
template <auto V>
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
当我们更改ic
为别名类型或使用未模板化的版本时,context
所有内容都按预期工作.那真的是铿锵的错误还是我错过了一些明显的东西?
PS.在[gcc]中,一切都按预期工作......
我知道这就像打开潘多拉盒子一样,但它并没有停止打扰我.考虑一个简单的例子:
#include <type_traits>
template <auto>
struct Foo: std::false_type { };
template <>
struct Foo<[](){return 1;}()>:std::true_type { };
int main() {
static_assert(Foo<1>::value);
}
Run Code Online (Sandbox Code Playgroud)
我知道lambdas不能在未评估的上下文中声明,但显然这不是这里的情况.什么是更奇怪的clang 5.0.0(我猜,首先部分支持constexpr lambda)确实编译它.
它是编译器错误还是C++ 17允许这样做?
考虑这段代码:
class Base {
public:
int foo(int x) const { return 2*x; }
};
class Derived : Base {
public:
using Base::foo;
};
Run Code Online (Sandbox Code Playgroud)
现在Derived
有一个公共方法 foo 并且可以调用它
Derived d;
d.foo(2); // compiles (as it should)
Run Code Online (Sandbox Code Playgroud)
但是,如果我通过指针使用该方法,我将无法执行任何操作:
Derived d;
(d.*&Derived::foo)(2); // does not compile because `Derived::foo` expects a pointer to `Base` and `Derived` cannot be casted to its private base class (without a C-style cast).
Run Code Online (Sandbox Code Playgroud)
对于这种行为是否有任何合乎逻辑的解释,或者可能是标准中的疏忽?
考虑最小的例子:
template <int>
struct bar { };
int main()
{
[](auto i) -> bar<i> { return {}; };
}
Run Code Online (Sandbox Code Playgroud)
甚至:
template <int>
struct bar {};
template <class I>
auto foo(I i) -> bar<i> {}
Run Code Online (Sandbox Code Playgroud)
clang编译两种形式没有问题,但gcc发现使用无效(例如1),(例如2)
这个问题可能看起来很愚蠢,但是参数的类型可以让constexpr转换运算符重载(在这种情况下,i
从传递给lambda/foo的值推导出的类型int
是以constexpr方式推导出来的),在这种情况下,不要强迫它做一些变通方法直接访问它...
考虑一个简单的例子:
int x;
template <template <auto> class TT>
struct Foo {
void foo() {
TT<(x)> tt;
static_cast<void>(tt);
}
};
template <decltype(auto)>
struct Bar { };
int main() {
Foo<Bar> foobar;
foobar.foo();
}
Run Code Online (Sandbox Code Playgroud)
[clang]似乎处理decltype(auto)
占位符的想法,尽管auto
在模板模板参数声明中使用没有问题.
[gcc]另一方面 - 不是很好:
prog.cc:6:13:错误:'x'的值在常量表达式中不可用
通常 - 根据标准预期哪种行为?或许一切皆有可能,而且代码格式不正确(这次我想不是,但不能明确地排除它)?
PS.很抱歉再次打破其中一个编译器;)
通过使用模板模板参数,可以将模板化的类传递给类,而无需在其参数上指定类型.我想知道有没有办法将函数的模板化签名传递给模板模板参数,以便能够专门考虑函数的哪个变体被认为是向前的.
要清楚 - 我知道我做不到:
template <class T>
void foo() { /*...*/ }
template <template <class...> class FooType>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo)> f;
}
Run Code Online (Sandbox Code Playgroud)
但不知何故,我希望能够将模板的模板签名传递给Foo
.它甚至可能吗?
根据[ temp.deduct.guide/3 ]:
(...)演绎指南应在与相应的类模板相同的范围内声明,对于成员类模板,具有相同的访问权限.(......)
#include <string>
template <class>
struct Foo {
template <class T>
struct Bar {
Bar(T) { }
};
Bar(char const*) -> Bar<std::string>;
};
int main() {
Foo<int>::Bar bar("abc");
static_cast<void>(bar);
}
Run Code Online (Sandbox Code Playgroud)
嵌套模板类的演绎指南的正确语法是什么?或者这个可能是正确的但是编译器还没有支持它?
#include <string>
template <class T>
struct Bar {
Bar(T) { }
};
Bar(char const*) -> Bar<std::string>;
int main() {
Bar bar("abc");
static_cast<void>(bar);
}
Run Code Online (Sandbox Code Playgroud) c++ ×10
templates ×7
c++17 ×6
auto ×1
c++11 ×1
c++14 ×1
local-class ×1