我有一个我称之为的函数:
literal<long[2]>({1, 2});
Run Code Online (Sandbox Code Playgroud)
我想写一个扩展到这个语句的宏,例如:
MYMACRO(long[2], {1, 2})
Run Code Online (Sandbox Code Playgroud)
不幸的是,预处理器不知道大括号匹配,所以它看到三个参数(第二个和第三个分别是{1和2}).
这是预处理器的已知限制,最简单的解决方案通常是在宏调用中添加额外的括号(如果可能).
但是,在这种情况下,将括号括起的初始化器放在括号内似乎改变了它的含义:
literal<long[2]>(({1, 2}));
(g++ 4.8) error: left operand of comma operator has no effect [-Werror=unused-value]
Run Code Online (Sandbox Code Playgroud)
这是GCC错误还是设计错误?有什么方法可以实现我想要的吗?
我可能应该更清楚原始问题的措辞.预处理器没有永久改变(甚至可变参数宏长期以来都是GCC扩展).在这种情况下实际的解决方法是有用的,但它们也是众所周知的,并不是我想要达到的目的.
我真的想知道是否有任何东西被添加到C++ 11中以专门解决这个问题(或者是疏忽?).考虑到在整个语言中使用大括号括起来的列表,宏观调用中的大括号的古怪处理现在似乎是一个更大的问题.
我特别恼火的是,将括号括在括号内的初始化列表中会改变它在用作函数参数时的解析方式.函数调用是否有任何其他参数不能括号?在编写将参数传递给函数的宏时,似乎是特殊情况.
我真的希望有人可以指出这是一个GCC错误,或解释为什么将括号括在括号内的初始化列表中必须改变其含义.
我正在使用转发构造函数创建一个瘦派生类.(请耐心等待,我必须使用缺少继承构造函数的GCC 4.7.2).
在第一次尝试时,我忘了添加explicit关键字并出错.有人可以解释为什么会发生这种特殊错误吗?我无法搞清楚事件的顺序.
#include <memory>
template<typename T>
struct shared_ptr : std::shared_ptr<T>
{
template<typename...Args>
/*explicit*/ shared_ptr(Args &&... args)
: std::shared_ptr<T>(std::forward<Args>(args)...)
{}
};
struct A {};
struct ConvertsToPtr
{
shared_ptr<A> ptr = shared_ptr<A>(new A());
operator shared_ptr<A> const &() const { return ptr; }
};
int main()
{
shared_ptr<A> ptr;
ptr = ConvertsToPtr(); // error here
return 0;
}
Run Code Online (Sandbox Code Playgroud)
错误:
test.cpp: In function ‘int main()’:
test.cpp:28:23: error: ambiguous overload for ‘operator=’ in ‘ptr = ConvertsToPtr()’
test.cpp:28:23: note: candidates are:
test.cpp:9:8: note: …Run Code Online (Sandbox Code Playgroud) 我有一个使用boost::shared_ptrs 的程序,特别是依赖于use_count执行优化的准确性.
例如,想象一个带有两个参数指针的加法运算,称为lhs和rhs.说他们都有类型shared_ptr<Node>.当需要执行添加时,我将检查use_count,如果我发现其中一个参数的引用计数恰好为1,那么我将重用它来执行操作.如果两个参数都不能重用,我必须分配一个新的数据缓冲区并执行不合适的操作.我正在处理庞大的数据结构,因此就地优化非常有用.
因此,我无法shared_ptr无理由地复制s,即每个函数都shared_ptr通过引用或const引用来获取s以避免失真use_count.
我的问题是这样的:我有时会有一个shared_ptr<T> &我想投的东西shared_ptr<T const> &,但是如何在不扭曲使用次数的情况下做到这一点? static_pointer_cast返回一个新对象而不是引用.我倾向于认为只投下整个就行了shared_ptr,如:
void f(shared_ptr<T> & x)
{
shared_ptr<T const> & x_ = *reinterpret_cast<shared_ptr<T const> *>(&x);
}
Run Code Online (Sandbox Code Playgroud)
我非常怀疑这符合标准,但正如我所说,它可能会奏效.有没有办法做到这一点,保证安全和正确?
更新以集中问题
批评设计无助于回答这篇文章.有两个有趣的问题需要考虑:
是否有任何保证(由作者boost::shared_ptr或标准,在案例中std::tr1::shared_ptr)shared_ptr<T>并且shared_ptr<T const>具有相同的布局和行为?
如果(1)为真,那么上面是reinterpret_cast的合法使用吗?我认为你很难找到一个为上面的例子生成失败代码的编译器,但这并不意味着它是合法的.无论您的答案是什么,您能否在C++标准中找到对它的支持?
在NumPy中,可以使用__array_priority__属性来控制作用于ndarray和用户定义类型的二进制运算符。例如:
class Foo(object):
def __radd__(self, lhs): return 0
__array_priority__ = 100
a = np.random.random((100,100))
b = Foo()
a + b # calls b.__radd__(a) -> 0
Run Code Online (Sandbox Code Playgroud)
但是,对于比较运算符而言,似乎不起作用。例如,如果将以下行添加到Foo,则永远不会从表达式中调用它a < b:
def __rlt__(self, lhs): return 0
Run Code Online (Sandbox Code Playgroud)
我意识到这__rlt__并不是Python的特殊名称,但我认为它可能有用。我尝试了所有的__lt__,__le__,__eq__,__ne__,__ge__,__gt__有和没有前面r,加上__cmp__了,但是我永远无法与NumPy调用它们。
这些比较可以覆盖吗?
为避免混淆,此处是NumPy行为的详细描述。首先,这是《 NumPy指南》书中所说的内容:
If the ufunc has 2 inputs and 1 output and the second input is an Object array
then a special-case …Run Code Online (Sandbox Code Playgroud) 可以通过嵌套括号括起的列表来创建多维初始值设定项,如{{1,2,3}, {4,5,6}}.接受此功能的函数可以使用嵌套std::initializer_lists 编写.
数据元素是否保证是连续的?
这是一个例子:
void f(std::initializer_list<std::initializer_list<int>> a)
{
for(auto const & p: a)
for(auto const & q: p)
std::cout << &q << std::endl;
}
int main()
{
f({{1,2,3}, {4,5,6}});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在我的机器上输出连续的地址.
0x400c60
0x400c64
0x400c68
0x400c6c
0x400c70
0x400c74
Run Code Online (Sandbox Code Playgroud)
有保证吗?
答案必须是否定的.
void g(std::initializer_list<int> a, std::initializer_list<int> b)
{
f({b,a});
}
int main()
{
g({1,2,3}, {4,5,6});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
0x400cdc
0x400ce0
0x400ce4
0x400cd0
0x400cd4
0x400cd8
Run Code Online (Sandbox Code Playgroud)