C++ 与msvc相比,键入擦除、委托和lambda函数
在下面的代码中,我使用了一种相对简单的类型擦除技术。类C++ 与msvc相比,键入擦除、委托和lambda函数,c++,c++11,templates,lambda,visual-studio-2015,C++,C++11,Templates,Lambda,Visual Studio 2015,在下面的代码中,我使用了一种相对简单的类型擦除技术。类解释器上下文ptr定义了一个“接口”,指向实现该接口的对象的指针可用于构造解释器上下文ptr。这允许多态性而不使用虚拟分派 这与一篇名为。另外,请在github上查看badair的项目 另外,如果您一开始不认识它,这里的+[](…)语法就是所谓的“正lambda”语法,这是一个很好的解释 以下是MCVE: #include <iostream> #include <string> #include <vector
解释器上下文ptr
定义了一个“接口”,指向实现该接口的对象的指针可用于构造解释器上下文ptr
。这允许多态性而不使用虚拟分派
这与一篇名为。另外,请在github上查看badair的项目
另外,如果您一开始不认识它,这里的+[](…)
语法就是所谓的“正lambda”语法,这是一个很好的解释
以下是MCVE:
#include <iostream>
#include <string>
#include <vector>
class interpreter_context_ptr {
void * object_;
void (*new_text_call_)(void *, const std::string &);
void (*error_text_call_)(void *, const std::string &);
void (*clear_input_call_)(void *);
public:
void new_text(const std::string & str) const {
this->new_text_call_(object_, str);
}
void error_text(const std::string & str) const {
this->error_text_call_(object_, str);
}
void clear_input() const { this->clear_input_call_(object_); }
template <typename T>
explicit interpreter_context_ptr(T * t)
: object_(static_cast<void *>(t))
, new_text_call_(+[](void * o, const std::string & str) {
static_cast<T *>(o)->new_text(str);
})
, error_text_call_(+[](void * o, const std::string & str) {
static_cast<T *>(o)->error_text(str);
})
, clear_input_call_(+[](void * o) { static_cast<T *>(o)->clear_input(); }) {
}
};
/***
* Tests
*/
struct A {
void new_text(const std::string & str) {
std::cout << "A: " << str << std::endl;
}
void error_text(const std::string & str) {
std::cout << "A! " << str << std::endl;
}
void clear_input() { std::cout << std::endl; }
};
struct B {
void new_text(const std::string & str) {
std::cout << "B: " << str << std::endl;
}
void error_text(const std::string & str) {
std::cout << "B! " << str << std::endl;
}
void clear_input() { std::cout << std::endl; }
};
int main() {
std::vector<interpreter_context_ptr> stack;
A a;
B b;
stack.emplace_back(&a);
stack.back().new_text("1");
stack.emplace_back(&b);
stack.back().new_text("2");
stack.emplace_back(&b);
stack.back().new_text("3");
stack.back().clear_input();
stack.pop_back();
stack.back().error_text("4");
stack.emplace_back(&a);
stack.back().error_text("5");
stack.pop_back();
stack.back().error_text("6");
stack.pop_back();
stack.back().new_text("7");
stack.back().clear_input();
stack.pop_back();
std::cout << "Stack size = " << stack.size() << std::endl;
}
结果MSVC仍然不高兴——主要的错误是神秘的
编译器找到了一个不需要的标识符。确保在使用标识符之前声明了它
初始值设定项可以用括号括起来。要避免此问题,请将声明符括在括号中或将其设为typedef
当编译器将表达式检测为类模板参数时,也可能会导致此错误;使用typename告诉编译器它是一个类型
以下是完整的日志:
Error(s):
source_file.cpp(27): error C2061: syntax error: identifier 'T'
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(655): note: see reference to function template instantiation 'interpreter_context_ptr::interpreter_context_ptr<A>(T *)' being compiled
with
[
T=A
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(918): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(917): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(929): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(928): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(30): error C2061: syntax error: identifier 'T'
source_file.cpp(32): error C2061: syntax error: identifier 'T'
但正如我在评论中所写,如果我真的要走这么远,我会感到非常惊讶。MSVC开发人员声称已经在上完全支持并实现了lambda函数。我认为应该包括在lambda的范围内引用环境模板参数。在这个问题的时候,Visual C++ 2015编译器在lambda上遇到了<代码>运算符+ < /代码>的问题。删除每个lambda前面的
+
符号可以编译此代码。它确实稍微改变了语义(表达式的有效类型略有不同),尽管我认为这并不重要
确保安装了最新的更新,以确保没有其他编译器/库错误让您无故浪费时间。MSVC在
+
中存在问题,因为它将lambda转换为多个函数指针调用约定类型;所以+
是不明确的
通常,删除+
会使代码“正常工作”,因为隐式强制转换操作符做了正确的事情,并且知道要将lambda强制转换到的指针的调用约定
这不是你唯一的问题。下一个问题是无状态lambda不能正确地访问周围上下文中可用的类型
MSVC 2015名义上只是一个C++11编译器。它有很多很多不正常的情况。随着编译器的更新,对这类事情的支持往往会大大提高;确保您拥有MSVC 2015 U3.1(有一个U3,然后是U3上的一个补丁,我称之为U3.1)
另一个次要细节是处理
T
是const
类型的情况。我变懒了,用(void*)t
替换静态_cast(t)
,因为它将在一个步骤中删除const和cast to void。或者你可以const_cast(static_cast(t))
或者类似的东西。你使用的是VS2015,它与Clang/C2编译器前端一起提供。如果您无法理解MSVC向您抛出的错误消息,请尝试其他编译器。请注意,Clang可能接受此代码,而MSVC不接受。那你就不走运了。但是如果不是,你肯定会得到一个更清晰的错误消息。嗯,不幸的是,看起来至少是真正的Clang和GCC接受这个代码没有警告,所以我的选择可能是不去的,虽然Clang /C2确实使用微软C++库,这可能是错误的原因。如果是这样的话,那就是一个库错误。另外,试着从lambda中删除+
,我已经读过了,在MSVC阻塞该构造之前。代码在没有它们的情况下编译,但请检查行为是否相同。@rubenvb:我的意思是,它怎么可能是库呢?interpreter\u context\u ptr
类在这里不使用标准库,保存std::string
,我认为这不相关,我认为我们可以用int
替换它(我想我可以测试一下)除非lambda函数的实现以某种方式依赖于msvc中的库,否则我看不出这会在哪里出现,这不应该只是核心语言功能吗?嗯,当您从lambda中删除+
es时,它会编译。所以我不确定其他所有的错误都来自哪里。
template <typename T>
explicit interpreter_context_ptr(T * t)
: object_(static_cast<void *>(t))
, new_text_call_([](void * o, const std::string & str) {
static_cast<T *>(o)->new_text(str);
})
, error_text_call_([](void * o, const std::string & str) {
static_cast<T *>(o)->error_text(str);
})
, clear_input_call_([](void * o) { static_cast<T *>(o)->clear_input(); }) {
}
Error(s):
source_file.cpp(27): error C2061: syntax error: identifier 'T'
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(655): note: see reference to function template instantiation 'interpreter_context_ptr::interpreter_context_ptr<A>(T *)' being compiled
with
[
T=A
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(773): note: see reference to function template instantiation 'void std::allocator<_Ty>::construct<_Objty,A>(_Objty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(918): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\xmemory0(917): note: see reference to function template instantiation 'void std::allocator_traits<_Alloc>::construct<_Ty,A>(std::allocator<_Ty> &,_Objty *,A &&)' being compiled
with
[
_Alloc=std::allocator<interpreter_context_ptr>,
_Ty=interpreter_context_ptr,
_Objty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(929): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE\vector(928): note: see reference to function template instantiation 'void std::_Wrap_alloc<std::allocator<_Ty>>::construct<interpreter_context_ptr,A>(_Ty *,A &&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(68): note: see reference to function template instantiation 'void std::vector<interpreter_context_ptr,std::allocator<_Ty>>::emplace_back<A*>(A *&&)' being compiled
with
[
_Ty=interpreter_context_ptr
]
source_file.cpp(30): error C2061: syntax error: identifier 'T'
source_file.cpp(32): error C2061: syntax error: identifier 'T'
class interpreter_context_ptr {
void * object_;
void (*new_text_call_)(void *, const std::string &);
void (*error_text_call_)(void *, const std::string &);
void (*clear_input_call_)(void *);
template <typename T>
struct helper {
static void new_text(void * o, const std::string & str) {
static_cast<T*>(o)->new_text(str);
}
static void error_text(void * o, const std::string & str) {
static_cast<T*>(o)->error_text(str);
}
static void clear_input(void * o) {
static_cast<T*>(o)->clear_input();
}
};
public:
void new_text(const std::string & str) const {
this->new_text_call_(object_, str);
}
void error_text(const std::string & str) const {
this->error_text_call_(object_, str);
}
void clear_input() const { this->clear_input_call_(object_); }
template <typename T>
explicit interpreter_context_ptr(T * t)
: object_(static_cast<void *>(t))
, new_text_call_(&helper<T>::new_text)
, error_text_call_(&helper<T>::error_text)
, clear_input_call_(&helper<T>::clear_input) {
}
};