我经常发现自己想写这样的代码:
class MyClass
{
public:
void addObject(std::unique_ptr<Object>&& newObject);
void removeObject(const Object* target);
private:
std::set<std::unique_ptr<Object>> objects;
};
Run Code Online (Sandbox Code Playgroud)
但是,很多std :: set接口对std :: unique_ptrs都没用,因为查找函数需要std :: unique_ptr参数(我显然没有这些参数,因为它们由集合本身拥有).
我可以想到两个主要的解决方案.
创建临时unique_ptr以进行查找.例如,上面的removeObject()可以实现如下:
void MyClass::removeObject(const Object* target)
{
std::unique_ptr<Object> targetSmartPtr(target);
objects.erase(targetSmartPtr);
targetSmartPtr.release();
}
Run Code Online (Sandbox Code Playgroud)将原始指针映射替换为unique_ptrs.
// ...
std::map<const Object*, std::unique_ptr<Object>> objects;
};
Run Code Online (Sandbox Code Playgroud)然而,对我来说,两者似乎都有点愚蠢.在解决方案1中,erase()不是noexcept,因此临时unique_ptr可能会删除它实际上不拥有的对象,而2需要不必要地为容器存储两倍.
我知道Boost的指针容器,但与现代C++ 11标准库容器相比,它们目前的功能有限.
我最近在阅读有关C++ 14的内容,并且遇到了"将异构比较查找添加到关联容器".但是形成我对它的理解,查找类型必须与键类型相当,但原始指针不能与unique_ptrs相比.
任何人都知道更优雅的解决方案或即将添加的C++解决了这个问题?
为什么在C11或C++ 11中没有UTF-8字符文字,即使有UTF-8字符串文字?我理解,一般来说,字符文字表示单个ASCII字符,它与单个八位字节UTF-8代码点相同,但C和C++都没有说编码必须是ASCII.
基本上,如果我读取标准权限,则无法保证'0'将表示整数0x30,但u8"0"必须表示字符序列0x30 0x00.
编辑:
我知道不是每个UTF-8代码点都适合char.这样的文字只对单八位字节代码点(aka,ASCII)有用,所以我猜这称为"ASCII字符文字"会更合适,所以问题仍然存在.我只是选择用UTF-8构建问题,因为有UTF-8字符串文字.我可以想象可以保证ASCII值的唯一方法就是为每个字符写一个常量,考虑到只有128个,这不会那么糟糕,但仍然......
我正在尝试根据N1570编写C11的lex/yacc语法.我的大部分语法都是从信息性语法摘要中逐字复制的,但是出现了一些yacc冲突.我设法解决了所有这些问题,除了一个:当'_Atomic'用作类型说明符和用作类型限定符时,似乎存在一些模糊性.
在说明符形式中,_Atomic紧跟着括号,所以我假设它与C的很少使用的语法有关,它允许声明符在括号中,从而允许括号立即跟随限定符.但我的语法已经知道如何区分typedef名称和其他标识符,所以yacc应该知道差异,不应该吗?
我不能为我的生活想到一个实际上是模棱两可的案例.
我怀疑它有帮助,但这是我使用yacc的-v标志时获得的相关状态输出."ATOMIC"显然是我的"_Atomic"的令牌名称
state 23
152 atomic_type_specifier: ATOMIC . '(' type_name ')'
156 type_qualifier: ATOMIC .
'(' shift, and go to state 49
'(' [reduce using rule 156 (type_qualifier)]
$default reduce using rule 156 (type_qualifier)
Run Code Online (Sandbox Code Playgroud) 我正在尝试从延迟渲染器中的深度值重建3D世界坐标,但我有一点时间.我在网上找到的大多数例子都假设了标准的透视转换,但我不想做出这样的假设.
在我的几何传递顶点着色器中,我使用以下方法计算gl_Position:
gl_Position = wvpMatrix * vec4(vertexLocation, 1.0f);
Run Code Online (Sandbox Code Playgroud)
在我的照明传递片段着色器中,我尝试使用以下方法获取世界坐标:
vec3 decodeLocation()
{
vec4 clipSpaceLocation;
clipSpaceLocation.xy = texcoord * 2.0f - 1.0f;
clipSpaceLocation.z = texture(depthSampler, texcoord).r;
clipSpaceLocation.w = 1.0f;
vec4 homogenousLocation = viewProjectionInverseMatrix * clipSpaceLocation;
return homogenousLocation.xyz / homogenousLocation.w;
}
Run Code Online (Sandbox Code Playgroud)
我以为我做对了,事实上,相机附近的物体似乎正确点亮了.但是我最近意识到,当我向远处移动时,物体被照亮,好像它们离相机更远,而不是它们实际上.我玩过我的灯光通道并验证我的世界坐标是唯一被误算的东西.
我不禁想到我的clipSpaceLocation.z和clipSpaceLocation.w是问题的根源,但我已经尝试了我能想到的每个变化来计算它们,上面的代码得到了最正确的结果.
任何想法或建议?
在我使用的所有现代C++编译器中,以下是合法的:
std::array<float, 4> a = {1, 2, 3, 4};
Run Code Online (Sandbox Code Playgroud)
我正在尝试创建具有类似构造语义的我自己的类,但我遇到了一个恼人的问题.考虑以下尝试:
#include <array>
#include <cstddef>
template<std::size_t n>
class float_vec
{
private:
std::array<float, n> underlying_array;
public:
template<typename... Types>
float_vec(Types... args)
: underlying_array{{args...}}
{
}
};
int main()
{
float_vec<4> v = {1, 2, 3, 4}; // error here
}
Run Code Online (Sandbox Code Playgroud)
当使用上面的int文字时,编译器会抱怨它无法隐式转换int为float.我认为它在这个std::array例子中起作用,因为给出的值是已知属于域内的编译时常量float.另一方面,可变参数模板int用于参数类型,转换发生在构造函数的初始化列表中,其中值在编译时是未知的.
我不想在构造函数中进行显式强制转换,因为这样就可以允许所有数值,即使它们不能表示float.
我能想到得到我想要的唯一方法是以某种方式具有可变数量的参数,但具有特定类型(在这种情况下,我想要float).我知道std::initializer_list,但我希望能够在编译时强制执行参数的数量.
有任何想法吗?我想要的C++ 11甚至可能吗?为C++ 14提出的任何新建议都能解决这个问题吗?
我正在尝试实现一个偏好系统,程序员可以在其中指定偏好名称、类型(布尔值、整数、字符串等),以及可选的默认值。我已经研究了一段时间但无法提出的是用于存储到磁盘/从磁盘加载的通用解决方案。我希望设计足够通用以处理多种格式(即文本文件、Windows 注册表或 Apple 的属性列表)。简单的解决方案是为每种存储格式制作转换器,并在已经选择存储格式时沿线某处制作转换器,迭代首选项并切换它们的类型。
有人告诉我在类型上执行 switch-case 不是一个好的解决方案,我理解为什么:如果我添加一个类型,我需要去修改所有那些 switch-case 块。那我应该怎么做呢?通常的答案是让被检查类型的对象实现一个公共接口并知道如何自己执行操作。
但这对我来说似乎很荒谬,让偏好值知道如何将自身存储在文本文件、Windows 注册表和 Apple 属性列表中。那只是移动问题。添加一个新类型需要我去修改转换器,如果我添加一个新转换器,我需要去修改所有类型!
我想这是一个常见的设计问题,但我找不到任何好的解决方案。
我目前正在尝试编写一个函数,它将任何类型的STL数组作为其参数之一.写它的显而易见的方法是:
template<typename T, int count>
void setArrayBufferData(GLenum usage, const std::array<T, count>& data) {
setArrayBufferData(usage, data.data(), sizeof(T) * count);
}
Run Code Online (Sandbox Code Playgroud)
这是另一个重载,它只是作为参考
void setArrayBufferData(GLenum usage, void* data, int size) {
glBufferData(GL_ARRAY_BUFFER, size, data, usage);
}
Run Code Online (Sandbox Code Playgroud)
函数定义编译得很好.但是,当我试着打电话的时候
std::array<int, 4> data;
setArrayBufferData(GL_STATIC_DRAW, data);
Run Code Online (Sandbox Code Playgroud)
我得到一个"没有匹配函数来调用'setArrayBufferData'"错误消息.我知道如果我在调用中指定模板参数它会工作,但我希望调用推断它们.我已经尝试过研究模板模板参数,一个更通用的声明,然后是std :: array专门化,以及我能想到的所有其他语法变体,但我似乎无法找到一种方法来获得我正在寻找的东西对于.它是否可能,如果可能,还需要做什么?
我正在尝试制作自己的C++矢量数学库,我有兴趣用SSE优化它.对于我的vec2和vec3数据类型,我不能直接存储__m128类型,因为它们必须是它们的预期大小,但是vec4呢?假设我的vec4类型看起来像这样(忽略16字节对齐要求以简化讨论):
union vec4 {
struct {float x, y, z, w;};
__m128 sse;
}
vec4 operator+(const vec4& left, const vec4& right) {
vec4 result;
result.sse = _mm_add_ps(left.sse, right.sse);
return result;
}
Run Code Online (Sandbox Code Playgroud)
这是建议的方式,还是有一些很大的理由不让我想不到?即,我应该这样做:
struct vec4 {
float x, y, z, w;
};
vec4 operator+(const vec4& left, const vec4& right) {
__m128 leftSSE = _mm_load_ps(reinterpret_cast<const float*>(&left));
__m128 rightSSE = _mm_load_ps(reinterpret_cast<const float*>(&right));
__m128 resultSSE = _mm_add_ps(leftSSE, rightSSE);
vec4 result;
_mm_store_ps(reinterpret_cast<float*>(&result), resultSSE);
return result;
}
Run Code Online (Sandbox Code Playgroud)
虽然我们在这里,我的理论vec2和vec3类型怎么样?首先将它们转换为vec4然后使用SIMD指令或单独处理它们的标量元素会更快吗?
我正在尝试在Rust中编写类似以下的函数:
fn double_and_square<'a, T>(x: &'a T) -> /* whatever the output type of `&t * &t` is */ {
let t = x + x;
&t * &t
}
Run Code Online (Sandbox Code Playgroud)
我希望它适用于T非类型的类型Copy.我需要指定不仅&'a T器具Add(容易),也表明其与局部变量的寿命输出类型的参考t工具Mul.
尝试#1(没有为中间类型指定生命周期):
fn double_and_square<'a, T>(x: &'a T) -> <&<&'a T as Add>::Output as Mul>::Output
where
&'a T: Add,
&<&'a T as Add>::Output: Mul,
{
let t = x + x;
&t * &t
}
Run Code Online (Sandbox Code Playgroud)
导致以下编译器错误:
error[E0106]: missing …Run Code Online (Sandbox Code Playgroud) 有没有办法通过本机互操作将 C# 对象引用(类类型,而不是结构)传入和传出 C++?
这是我的用例:
我正在尝试用 C# 编写游戏引擎,但想使用本机 (C++) 物理库。物理库维护它自己的所有物理身体的内部状态,并让用户将少量数据(一个指针)与每个身体相关联。在物理模拟滴答之后,库提供所有移动的物理实体的列表。我想遍历这个列表并将所有更改中继到相应的 C# 对象。
问题是:将 C# 中的对象与 C++ 中的相应物理体相关联的最佳方法是什么?
我可以想到几种方法:
有没有我不知道的选项 3 之类的机制?C++/CLI 不是一个选项,因为我想支持没有它的平台。
我对此感到非常困惑.我正在尝试渲染到屏幕外的纹理,以便我可以执行一些后期处理,但甚至无法获得该纹理以不加修改地绘制到屏幕上.我目前正在iPhone模拟器上瞄准OpenGL ES 2.0.
我已经将问题缩小到GLSL的texture2D()函数返回vec4(0,0,0,1),因为如果我用任何常量颜色替换该调用,屏幕将填充指定的颜色.创建纹理,绑定到纹理单元0,分配其存储,将其min和mag滤波器设置为NEAREST,并将sampler2D uniform设置为0.
我已经尝试删除所有渲染到纹理代码并显式初始化它的数据,我得到相同的结果,如果直接定位屏幕帧缓冲区,我得到我期望的图像,所以我相当自信纹理的数据是所有这些都是在我尝试从中抽样的时候定义的.
我已经尝试确保我的纹理在渲染时没有绑定到任何纹理单元,但这并没有什么区别.
我也试过glEnable(GL_TEXTURE_2D),但我的印象是ES 2.0无关紧要.反正它没有帮助.
我实际上是在OpenGL ES 2.0中使用我自己的瘦C++包装器库,但是如果你很了解OpenGL ES 2.0,那么这段代码中发生的事情应该是清楚的.我为代码不是普通的OpenGL道歉; 我的下一个调试步骤是在没有我的包装器库的情况下重新编写代码.我只是想知道我是否犯了任何跳出来的骨头错误.
但是,在最后一次drawArrays调用我设置的所有状态变量之前,我已经添加了普通的OpenGL glGet*()查询,并且所有内容都按预期设置.
代码中唯一不那么显而易见的部分是Smart <>对象.它们只是包装GL对象引用和引用数组,并在它们的析构函数中调用它们相关的glDelete*().
#include <tsvl/vec.hpp>
using namespace tsvl;
#include <tsgl2/Context.hpp>
#include <tsgl2/Smart.hpp>
using namespace tsgl2;
#include <array>
#include <exception>
#include <string>
using namespace std;
#define SHADER_SOURCE(text) "#version 100\n" #text
namespace {
const AttributeLocation vertexPositionAttributeLocation(0);
const string vec2PassthroughVertexShaderSource = SHADER_SOURCE(
attribute vec2 vertexPosition;
void main() {
gl_Position = vec4(vertexPosition, 0, 1);
}
);
const string greenFragmentShaderSource = SHADER_SOURCE(
void main() {
gl_FragColor = vec4(0, 1, …Run Code Online (Sandbox Code Playgroud) 当返回的变量超出函数范围时,我对C++返回值优化有很好的把握,但是返回成员变量呢?请考虑以下代码:
#include <iostream>
#include <string>
class NamedObject {
public:
NamedObject(const char* name) : _name(name) {}
std::string name() const {return _name;}
private:
std::string _name;
};
int main(int argc, char** argv) {
NamedObject obj("name");
std::cout << "name length before clear: " << obj.name().length() << std::endl;
obj.name().clear();
std::cout << "name length after clear: " << obj.name().length() << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
哪个输出:
name length before clear: 4
name length after clear: 4
Run Code Online (Sandbox Code Playgroud)
显然,这个obj.name().clear()行为是临时副本,但是电话obj.name.length()呢?std::string::length()是const成员函数,因此保证不修改字符串的状态.那么,应该允许编译器不复制成员变量并直接使用它来调用const成员函数,这似乎是合理的.现代C++编译器是否进行了这种优化?有什么理由不应该或不能制作?
编辑:
为了澄清,我不是在询问标准回报值优化是否适用于此; …