我有一个结构,我传递给我的应用程序,其中包含一堆回调函数:
typedef struct {
std::function<void (void)> f1;
std::function<void (int)> f2;
std::function<int (float *)> f3;
// ... and so on
} CallbackTable;
Run Code Online (Sandbox Code Playgroud)
我通过将不同的函数绑定到各种回调来处理应用程序中的状态控制,具体取决于当前的系统状态; 它工作正常.
我现在要做的是添加一些带有包含可变数量参数的签名的额外回调,类似于printf:例如,
std::function<int (const char * format, ...)> printToStdOut;
Run Code Online (Sandbox Code Playgroud)
这不起作用.在Visual C++中,我收到一条错误消息,指出:
error C2027: use of undefined type 'std::_Get_function_impl<_Fty>'
Run Code Online (Sandbox Code Playgroud)
我仍然在感受这个C++语法领域,并且非常感谢我对如何从这里开始的任何建议.我的首要目标是能够按以下方式拨打电话:
myCallbackTable.printToStdOut("I've just eaten %d bananas\r\n", nBananas);
Run Code Online (Sandbox Code Playgroud)
...并根据系统状态将输出定向到控制台,文件或GUI窗口.
I\xe2\x80\x99m 尝试使用新的 VS_DEBUGGER_WORKING_DIRECTORY 和 VS_DEBUGGER_COMMAND 属性来促进在 CMake 生成的 Visual Studio 项目文件(在我的例子中为 Visual Studio 2013)中进行调试。
\n\n我的配置中的其他所有内容都有效,除了 this\xe2\x80\xa6
\n\nI\xe2\x80\x99ve 从 \xe2\x80\x98regular\xe2\x80\x99 Visual Studio 项目文件(即不是从 CMake 生成的)中注意到,在 \xe2\x80\x9cConfiguration Properties/Debugging\xe2\x80 \x9d 对话框中,\xe2\x80\x98Command\xe2\x80\x99 和 \xe2\x80\x98Working Directory\xe2\x80\x99 字段默认分别使用 $(TargetPath) 和 $(TargetDir) 填充。所以在我的 CMakeLists.txt 文件中,我有:
\n\nset_target_properties(myApplication PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)"\n VS_DEBUGGER_COMMAND "$(TargetPath)"\n VS_DEBUGGER_ENVIRONMENT "%PATH%;C:\\\\Qt\\\\5.9.7\\\\msvc2013_64\\\\bin")\n
Run Code Online (Sandbox Code Playgroud)\n\n[事实上,我已经尝试过使用和不使用 $(TargetDir) 和 $(TargetPath) 周围的引号,并且每次结果都是相同的;它们在道路上是绝对必要的。]
\n\n然后,我构建应用程序,转到 \xe2\x80\x9cConfiguration Properties/Debugging\xe2\x80\x9d 对话框,并验证它看起来与普通项目文件完全相同,其中包含 $(TargetDir) 和 $ (TargetPath) 正好出现在他们应该做的地方。但它不起作用;当我尝试调试时,收到一条消息“无法开始调试。请检查您的调试器设置...”
\n\n\n\n因此,我从对话框中删除文本 $(TargetDir) 和 $(TargetPath),然后像以前一样再次输入它们:然后它就完美运行了。
\n\n\n\n我究竟做错了什么?
\n我正在使用GNU make使用Microsoft Visual C++构建项目,我希望能够从任何CMD窗口运行它,而不必打开预先配置的路径(和各种其他环境变量)预先配置的窗口通过批处理文件.理想情况下,我想在makefile本身中定义相关的环境变量,所以我需要做的就是弹出一个CMD窗口并输入"make".
总的来说这是直截了当的,但我正在与PATH斗争; 到目前为止,我尝试采用标准PATH变量(在操作系统中定义)并将路径附加到各种构建工具的所有语法都失败了.
而不是通过我尝试过的六种或七种不同的语法 - 其中一些给出了错误信息,其中一些没有给出错误信息但只是没有用 - 我会明白地问这个问题:
到目前为止,我最接近成功的是:
LINK ="C:\ Program Files(x86)\ Microsoft Visual Studio 9.0\VC\bin\link.exe"
...并用$(LINK)替换对"link.exe"的所有后续引用,但这会失败,因为link.exe具有各种依赖项(例如mspdb80.dll),这些依赖项也必须在路径上.
我有一个从C程序调用的Fortran DLL,我的一个程序需要定期调用由C程序提供的回调函数.我目前在它的'简单'形式下运行良好,但我希望能够将我的回调指针存储在派生类型中,以便它可以更容易地在我的Fortran代码中传递.到目前为止,我尝试过的任何东西似乎都没有用.
首先,这是我目前所拥有的,这确实有效:
从C(OK,实际上是C++)程序开始,回调的头部原型是:
typedef void (*fcb)(void *)
Run Code Online (Sandbox Code Playgroud)
Fortran调用的原型是:
extern "C" __declspec(dllexport) int fortran_function(int n,
uchar *image_buffer,
fcb callback,
void *object);
Run Code Online (Sandbox Code Playgroud)
实际的回调函数是:
void callback(void* pObject)
{
// Cast the void pointer back to the appropriate class type:
MyClass *pMyObject = static_cast<MyClass *>(pObject);
pMyObject -> updateImageInGUI();
}
Run Code Online (Sandbox Code Playgroud)
并且从C++调用Fortran代码是:
int error = fortran_function(m_image.size(), m_image.data, callback, this);
Run Code Online (Sandbox Code Playgroud)
其中m_image
是图像数据的数组,它是当前对象的成员属性.会发生什么是C++将原始图像数据传递给Fortran DLL并要求Fortran处理它,因为这需要很长时间Fortran定期更新图像缓冲区并调用回调来刷新GUI.无论如何,继续前进到Fortran端,我们为C回调定义了一个接口:
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
type(c_ptr), intent(in) :: c_object
end subroutine c_callback
end interface
Run Code Online (Sandbox Code Playgroud)
并定义我们的主要Fortran例程:
integer(c_int) …
Run Code Online (Sandbox Code Playgroud) 在C++中编写模板基类时,这是一个关于样式和安全性的相当普遍的问题.但是,请耐心等待,最后有一个具体问题......
我有一个模板基类,当类型T是基本类型(int,float等)时,它完全实现了所需的功能.但是,如果T不是原始的(例如,如果T是需要使用一组特定参数调用的构造函数的类),则需要覆盖某些方法,因此将它们声明为虚拟模板.模板还包含一个纯虚方法,它强制它是抽象的,所以为了使用它必须从以下派生:基于基本类型的派生类可以使用提供的所有方法并仅覆盖纯虚拟方法,而基于非基本类型的派生类应覆盖所有虚方法.
例如:
template <typename T> class myTemplate
{
public:
// Constructor:
myTemplate<T>();
// Destructor:
virtual ~myTemplate();
// General function, valid for all classes derived from this:
void printMe()
{
printf("Hello, I'm from the template\r\n");
}
// Primitive function, must be overridden for non-primitive types:
virtual T DoSomething(const T& myClass)
{
T result = result + static_cast<T>(1);
return result;
}
// Primitive function, must be overridden for non-primitive types:
virtual T DoSomethingElse(const T& myClass)
{
T result = …
Run Code Online (Sandbox Code Playgroud) 我希望能够使用带有std :: vector的自定义分配器,以便在堆栈上存储小数据缓冲区(例如,小于1024字节),并且只有更长的向量存储在堆上.作为拥有Fortran背景的人,每次我必须在五行子程序的持续时间内进行堆内存分配以存储六个元素时,它会让我感到身体疼痛!
Howard Hinnant发布了他的short_alloc分配器,它正是我正在寻找的东西,如果我用gcc编译它就可以了.但是,在Visual C++中,我无法编译它.在Visual C++ 2013中,部分问题是太多的C++ 11关键字不受支持,但即使我已经#DEFINE'd所有这些关键字,我仍然遇到了问题.今天我尝试在Visual C++ 2015 CTP 5中进行编译,现在所有关键字都得到了支持,但编译最终因同样的原因而失败.
问题是:由于一个我不能声称完全理解的原因,Hinnant的代码默认复制构造函数但删除了复制赋值运算符:
short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete;
Run Code Online (Sandbox Code Playgroud)
尝试编译时,这会在Visual C++中触发以下错误:
xmemory0(892): error C2280: 'short_alloc<int,1024> &short_alloc<1024>::operator =(const short_alloc<1024> &)': attempting to reference a deleted function
Run Code Online (Sandbox Code Playgroud)
令我更加困惑的是,如果我修改Hinnant的代码来说
short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = default;
Run Code Online (Sandbox Code Playgroud)
...然后我仍然获得完全相同的错误消息.
作为参考,这是我的测试代码:
#include <iostream>
#include <vector>
#include "short_alloc.h"
void populate_the_vector(std::vector<int, short_alloc<int, 1024> > &theVector)
{
arena<1024> B;
std::vector<int, short_alloc<int, 1024> > anothertestvec{(short_alloc<int, 1024>(B))};
anothertestvec.resize(10);
for (int …
Run Code Online (Sandbox Code Playgroud) 我\xe2\x80\x99m对libtiff相当陌生,但我\xe2\x80\x99已经设法获得tiff文件\n保存和打开没有太多麻烦。
\n\n现在,我\xe2\x80\x99m雄心勃勃,并尝试将自定义标签添加到我的文件中。我\xe2\x80\x99ve\n阅读了文档(请参阅此处)并编写了一些测试代码,这些代码编译时没有\n错误,但在运行时失败,并在第一次调用\n具有自定义字段的 TIFFSetField 时发生访问冲突(调用 TIFFSetField带有\n标准字段就可以了)。
\n\n我的测试代码如下:不到 100 行,唯一的外部依赖项(除了 libtiff)是我从 .pgm 文件打开测试图像的代码。谁能指出我\xe2\x80\x99m 做错了什么?顺便说一句,我正在使用 libtiff 4.0.3。
\n\n#include "stdafx.h"\n#include "PGM.h" // Just for reading in the test image\n#include "tiffio.h"\n\n// There are a number of TIFF-related definitions we need to make in order to support the custom tags\n// that we want to include in our files. The form of these definitions and subroutines comes straight\n// out of the libtiff documentation, and the values of the custom tags themselves come …
Run Code Online (Sandbox Code Playgroud) 我有两个子例程重载,该子例程采用占用几兆动态内存的类型参数,并具有移动构造函数和赋值运算符:
// Version intended for use when we the caller has
// deliberately passed an rvalue reference using std::move
void MyClass::setParameter(MyMoveableType &&newParameter)
{
m_theLocalParameter = std::move(newParameter);
}
// Version intended for use when the caller has passed
// some other type of value which shouldn't be moved
void MyClass::setParameter(MyMoveableType newParameter)
{
m_theLocalParameter = std::move(newParameter);
}
Run Code Online (Sandbox Code Playgroud)
其意图显然是,第一个重载将 newParameter 的内容从子例程链上的任何地方移动 - 调用 newParameter 对象,而第二个重载创建 newParameter 的全新副本(或调用复制省略以避免在适当的情况下这样做,例如,参数实际上是函数的返回值),然后将副本移动到本地数据成员中,从而避免进一步的复制。
但是,如果我尝试使用第一个重载实际将对象移动到我的类中:
{
MyClass theDestination;
MyMoveableType theObject
...
// ...Various actions which populate theObject...
...
TheDestination.setParameter(std::move(theObject));
... …
Run Code Online (Sandbox Code Playgroud) 在我的应用程序套件中,我从源代码构建 Libtiff,然后将其链接到我自己编写的应用程序。Libtiff 的 CMakeLists.txt 文件指定静态库进入库位置 CMAKE_INSTALL_FULL_LIBDIR,由 CMake 的 GNUInstallDirs 选项确定。
当我第一次构建和测试我的应用程序时,我在 Debian 中这样做,并且在此平台上 CMAKE_INSTALL_FULL_LIBDIR 设置为 ${CMAKE_INSTALL_PREFIX}/lib。很好,所以在我自己的应用程序的 CMakeLists.txt 文件中,我告诉它在那里搜索静态 tiff 库。没问题...
现在,我已将相同的构建套件应用于 Red Hat Linux 平台(Pengwin Enterprise for WSL),结果发现此处 CMAKE_INSTALL_FULL_LIBDIR 设置为 ${CMAKE_INSTALL_PREFIX}/lib 64。我检查了CMake 文档,似乎说实际上“lib”或“lib64”的选择是自动确定的并且与平台相关。
那么,在我自己的应用程序的 CMakeLists.txt 文件中,有没有办法找出它在我当前平台上的位置?否则我该如何猜测去哪里寻找图书馆呢?我环顾四周,但找不到保存平台相关字符串的 CMAKE 标准变量,所以我唯一能想到的是:
...但这两种方法看起来都笨拙不雅,肯定有更好的方法。
对于嵌入式应用程序,我试图使用ANSI C实现结构的先进先出(FIFO)队列.最直接的方法似乎是通过实现链表,以便每个结构包含指向队列中下一个的指针.因此我将结构本身定义为:
typedef enum { LED_on, LED_off, etc } Action;
typedef struct Queued_Action QueuedAction;
struct Queued_Action
{
Action action;
int value;
QueuedAction *nextAction;
};
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.如果我将指向队列中第一个和最后一个项目的指针定义为:
QueuedAction *firstAction;
QueuedAction *lastAction;
Run Code Online (Sandbox Code Playgroud)
...然后我希望能够通过声明(例如)向队列添加新动作:
if (!add_action_to_queue(LED_on, 100, &lastAction))
printf("Error!\n);
Run Code Online (Sandbox Code Playgroud)
...所以在返回时,lastAction将是指向队列中新创建的最后一个操作的指针.因此,将操作添加到队列的例程如下所示:
int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
QueuedAction *newQueuedAction;
// Create a new action in memory
if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
return 0;
// Make the old 'lastAction' point to the new Action,
// and the new Action to point to …
Run Code Online (Sandbox Code Playgroud) 我正在编译一个项目,该项目依赖于其他几个开源项目(特别是 Zlib 和 LibTIFF),为此提供了 Windows 生成文件(旨在与 nmake 一起使用)。我想这样安排,每当我对我的项目执行“重建”时,开源项目也会用适当的配置(调试/发布、32/64 位等)重建。
我自己的项目相当简单,但并非微不足道。我试图弄清楚如何直接或使用 CMake 生成我自己的 nmake 生成文件,从而浪费了我最初的几天。尽管对 GNU make 有相当多的经验,但这让我失去了生存的意愿。从康复中心出来后,我决定坚持使用 Visual Studio 项目文件来构建我自己的项目,并定义一个“预构建事件”以在供应商为我的开源库提供的 makefile 上执行 nmake。
例如,在我的 32 位版本构建的 Visual Studio 2010 项目页面中,使用英特尔 C++ 编译器,我将预构建事件命令行编写为:
call "C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\ipsxe-comp-vars.bat" ia32 vs2010
cd ..\..\..\zlib-1.2.8
nmake /f win32\Makefile.msc zlib.lib
cd ..\tiff-4.0.3
nmake /f Makefile.vc lib
Run Code Online (Sandbox Code Playgroud)
(我意识到我也可以将上述内容放入批处理文件中,然后调用批处理文件,但我不想给自己另一个文件来跟踪)。无论如何,这很好用,除了一件事:如果我决定更改我的配置,我想在两个库上执行“nmake clean”,以确保它们是用我的新配置重建的,大致上的:
call "C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\ipsxe-comp-vars.bat" ia32 vs2010
cd ..\..\..\zlib-1.2.8
IF "%BUILDACTION%"=="REBUILD" nmake /f win32\Makefile.msc clean
nmake /f win32\Makefile.msc zlib.lib
cd ..\tiff-4.0.3
IF "%BUILDACTION%"=="REBUILD" …
Run Code Online (Sandbox Code Playgroud) 我熟悉的原则(例如,从这个答案 和这一个),当一个类有一个移动构造函数和/或移动赋值操作符,其默认的拷贝构造函数和拷贝赋值运算符将被删除.但是,在我看过的例子中,可以通过显式定义新的复制构造函数和赋值运算符来解决这个问题.
在我的特定情况下,我有一个类,它是通过C样式结构和模板类的联合继承派生的.复制和移动赋值运算符在模板中显式定义,而复制和移动构造函数在类本身中显式定义.换句话说,一切都是明确定义的,尽管并非都在同一个地方.这是一些示例代码:
typedef struct {
int n;
} myStruct;
template <typename T> class myTemplate
{
public:
// Default constructor
myTemplate<T>() : t_n(nullptr) {}
// Cannot create copy or move constructors in template, as cannot
// access the 'n' member directly
// Copy assignment operator
myTemplate<T> & operator=(const myTemplate<T> &source)
{
if (this != &source)
{
*t_n = *(source.t_n);
}
return *this;
}
//! Move assignment operator
myTemplate<T> & operator=(myTemplate<T> &&source)
{
if (this != …
Run Code Online (Sandbox Code Playgroud) 如果我理解正确,那么对象'A'定义如下:
typedef struct {
int n;
float *p;
} myStruct;
myStruct A;
Run Code Online (Sandbox Code Playgroud)
是一个聚合,其内存布局与对象'B'完全相同,定义如下:
template <typename T> class myTemplateClass
{
public:
int n;
T* p;
};
myTemplateClass<float> B;
Run Code Online (Sandbox Code Playgroud)
那么,是否有更优雅的分配方式
A = B;
Run Code Online (Sandbox Code Playgroud)
而不是写
A = *(reinterpret_cast< myStruct *>(&B));
Run Code Online (Sandbox Code Playgroud)
每次?
我的理由是我必须调用一个库函数,该函数使用"myStruct"形式的参数公开一个接口,从代码中以myTemplateClass的形式保存我的数据是非常自然的.
c++ ×6
c ×4
c++11 ×3
cmake ×2
libtiff ×2
makefile ×2
templates ×2
aggregation ×1
allocation ×1
batch-file ×1
c89 ×1
fifo ×1
fortran ×1
inheritance ×1
interop ×1
memory ×1
msbuild ×1
nmake ×1
path ×1
pengwin ×1
pragma ×1
std-function ×1
struct ×1
tiff ×1
visual-c++ ×1