在这个例子中:
template<class T>
struct S : T
{
using T::X;
};
Run Code Online (Sandbox Code Playgroud)
T::X
是指部件上的从属名称X
在T
.如果S<T>
实例化为T = X
:
struct X
{
X(int) {}
};
...
S<X> s(42);
Run Code Online (Sandbox Code Playgroud)
using声明是否会成为继承构造函数?
Clang拒绝代码DEMO,而g ++接受它.
请注意,如果我们写:
using T::X::X;
Run Code Online (Sandbox Code Playgroud)
两个编译器都接受代码并将其视为继承构造函数.被using T::X
允许通过标准成为继承,构造函数?
c++ templates using-declaration language-lawyer inheriting-constructors
在C++ 14中,广义lambda捕获让我们做:
template<class T>
auto pack(T t)
{
return [t=std::move(t)](auto&& f){f(t);};
};
Run Code Online (Sandbox Code Playgroud)
但它没有玩param-pack:
template<class... T>
auto pack(T... t)
{
return [t=std::move(t)...](auto&& f){f(t...);};
};
Run Code Online (Sandbox Code Playgroud)
是否有任何特殊语法或进一步的标准提案来解决这个问题?
标准是否允许以下内容?
#include <iostream>
extern int a;
auto a = 3;
int main(int, char**)
{
std::cout << a << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请考虑以下代码:
#include <array>
struct T
{
T() = delete;
};
int main()
{
std::array<T, 0> a;
a.size();
}
Run Code Online (Sandbox Code Playgroud)
我们默认初始化一个0大小的数组.由于没有元素,因此不T
应该调用构造函数.
但是,Clang仍然需要T
默认构造,而GCC接受上面的代码.
请注意,如果我们将数组初始化更改为:
std::array<T, 0> a{};
Run Code Online (Sandbox Code Playgroud)
Clang这次接受了.
非默认构造是否可以T
防止std::array<T, 0>
默认构造?
这类似于问题,但更具体的情况.这次,没有编译器按预期工作.
template<class T>
struct nondeduced
{
using type = T;
};
template<class T>
using nondeduced_t = typename nondeduced<T>::type;
template<class... T, class U>
void f(void(*)(nondeduced_t<T>..., U)) {}
void g(int, char) { }
int main()
{
f<int>(g); // error?
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,T
无法推导出参数包,但编译器应该能够U
在显式参数替换pack之后推导出T
(即int
在这种情况下为single ).
预计上述内容也可以在没有nondeduced_t
诀窍的情况下工作:
template<class... T, class U>
void f(void(*)(T..., U)) {}
Run Code Online (Sandbox Code Playgroud)
因为T
根据[temp.deduct.type] p5,参数包已经在非推导的上下文中
未推断的上下文是:
- 函数参数包,不会出现在参数声明列表的末尾.
不幸的是,我测试过的编译器(g ++/clang)都没有接受代码.值得注意的是,下面的内容适用于g ++和clang.
template<class... T>
void f(void(*)(nondeduced_t<T>..., char)) {}
Run Code Online (Sandbox Code Playgroud)
而且,这对两者都不起作用:
template<class... …
Run Code Online (Sandbox Code Playgroud) c++ language-lawyer variadic-templates c++11 template-argument-deduction
考虑这个例子:
struct B { operator int(); };
template<class T>
struct X:B
{
using B::operator T;
};
Run Code Online (Sandbox Code Playgroud)
请注意,如果基类型是相关的,则所有编译器都接受以下代码:
template<class T>
struct B { operator T(); };
template<class T>
struct X:B<T>
{
using B<T>::operator T;
};
Run Code Online (Sandbox Code Playgroud) 我认为它应该,因为它对正确性很重要.但是,我很惊讶地看到了Clang的输出.请考虑以下代码:
#include <iostream>
struct S
{
int i;
S(int i) : i(i) {}
S(S&&)
{
std::cout << "S(S&&)\n";
}
S(S const&) = delete;
};
S f()
{
S s{42};
std::cout << &s << "\n";
return s;
}
int main()
{
S s{f()};
std::cout << &s << "\n";
std::cout << s.i << "\n";
}
Run Code Online (Sandbox Code Playgroud)
我们定义了一个移动ctor S
来检查是否S(S&&)
被调用,如果没有,则应用NRVO.
我们从GCC看到的结果是:
0x7ffc3ed7b5ac
0x7ffc3ed7b5ac
42
Run Code Online (Sandbox Code Playgroud)
应用NRVO并且它们采用相同的地址,这是预期的.
但是,Clang的输出:
0x7fff908bbcc8
0x7fff908bbcf8
42
Run Code Online (Sandbox Code Playgroud)
应用NRVO但地址不同.
如果你想知道为什么有相同的地址是重要的 - 这是因为某些对象可能在构造时对其地址进行一些注册,如果对象被移动,则应该通知它(例如通过move-ctor).
应用NRVO但具有不同的存储器地址因此使其形成不良.这明显违反了合同 - 没有调用自定义移动/复制ctor,编译器如何将S的数据"复制"到另一个地方?
这是Clang的一个错误吗?
如果我们添加一个析构函数S
,例如 …
下面的代码说明了我的担忧:
#include <iostream>
struct O
{
~O()
{
std::cout << "~O()\n";
}
};
struct wrapper
{
O const& val;
~wrapper()
{
std::cout << "~wrapper()\n";
}
};
struct wrapperEx // with explicit ctor
{
O const& val;
explicit wrapperEx(O const& val)
: val(val)
{}
~wrapperEx()
{
std::cout << "~wrapperEx()\n";
}
};
template<class T>
T&& f(T&& t)
{
return std::forward<T>(t);
}
int main()
{
std::cout << "case 1-----------\n";
{
auto&& a = wrapper{O()};
std::cout << "end-scope\n";
}
std::cout << "case 2-----------\n";
{ …
Run Code Online (Sandbox Code Playgroud) 例:
int main()
{
int a = 0;
struct X
{
decltype(a) a;
};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该decltype(a)
指的是本地a
的main
,而成员,它声明股相同的名称.
Clang编译没有任何问题,MSVC14也是如此.
G ++抱怨它,添加-fpermissive
使它通过
prog.cc:6:21: error: declaration of 'int main()::X::a' [-fpermissive]
decltype(a) a;
^
prog.cc:3:9: error: changes meaning of 'a' from 'int a' [-fpermissive]
int a = 0;
Run Code Online (Sandbox Code Playgroud)
哪种行为符合标准?
现在我们知道,越界 - 指针算术具有未定义的行为,如本SO问题所述.
我的问题是:我们可以通过转换为std :: uintptr_t进行算术运算然后转换回指针来解决这种限制吗?是保证工作吗?
例如:
char a[5];
auto u = reinterpret_cast<std::uintptr_t>(a) - 1;
auto p = reinterpret_cast<char*>(u + 1); // OK?
Run Code Online (Sandbox Code Playgroud)
真实世界的用法是优化偏移内存访问 - 而不是p[n + offset]
我想做的offset_p[n]
.
编辑使问题更明确:
给定一个p
char数组的基指针,如果p + n
是一个有效的指针,将reinterpret_cast<char*>(reinterpret_cast<std::uintptr_t>(p) + n)
保证产生相同的有效指针?