MSVC++ Compiler Error C2892? - visual-c++

int main() {
struct local {
template<class T> // This line generates C2892 error.
void f() {}
};
}
Why I cannot use template member in local classes and structures? What causes such restrictions in Visual C++?

C++03 14.5.2/2 "Member templates" says:
A local class shall not have member templates
(same in C++98 and C++11). I don't know what the rationale is.

Related

Why doesn't __declspec(novtable) work on a template specialization?

I have a base class for a generic callable that I'm marking __declspec(novtable):
template<class F> struct callable;
template<class R, class... T>
struct __declspec(novtable) callable<R(T...)>
{ virtual R operator()(T...) volatile { return R(); } };
but somehow this does not error like it's supposed to:
int main()
{
auto temp = new callable<void()>();
temp->operator()();
}
Why is novtable not working?
Apparently Visual C++ looks at __declspec(novtable) on the template, not its specializations!
This doesn't make sense to me (is it a bug?), but the "solution" is to write this:
template<class F> struct __declspec(novtable) callable;

Define a static boolean in Rust from std::env::consts::OS=="windows"

I'd like to create a global static boolean value called IS_WINDOWS in a Rust file:
lazy_static! {
pub static ref IS_WINDOWS: bool = std::env::consts::OS=="windows";
}
However, when I do this, anything that references the IS_WINDOWS value from elsewhere doesn't see it as a bool, they instead see it as a custom IS_WINDOWS struct, i.e. trying to do:
if crate::globals::IS_WINDOWS {
}
...results in error:
mismatched types
expected `bool`, found struct `globals::IS_WINDOWS`
Turns out, all I needed to do is use * to dereference the static variable:
if *crate::globals::IS_WINDOWS {
}

Heterogenous containers in Rust for a graph

I am a C++ programmer learning Rust, and one of my main use cases is a graph-based computation engine. In my graph I have store a homogeneous type, and then I derive from this with a more specific type e.g. in C++
class BaseNode {
public:
BaseNode(std::vector<std::shared_ptr<BaseNode>>& parents);
virtual ~BaseNode() = default;
virtual void update();
const std::vector<std::shared_ptr<BaseNode>>& parents() const;
...
};
template<typename T>
class TypedNode<T> : public BaseNode {
public:
const T& value() const { return value_; }
...
private:
T value_;
}
The idea is that the graph is traversed and update() is called on each node. The node knows what each of its parents "true type" is and so in its update() can do something like static_cast<TypedNode<DataBlob>>(parents()[0]).
How do I achieve something like this in Rust?
I thought about having a design like this:
trait BaseNode {
fn parents(&self) -> &Vec<dyn BaseNode>;
}
trait TypedNode<T>: BaseNode {
fn value(&self) -> &T;
}
But I read that I won't be able to cast the "trait object" from a BaseNode into a TypedNode<T>. (Or can I do it somehow using unsafe?). The other alternative I thought would be to have a struct that stores the data in Any and then to cast that, but does that incur some runtime cost?
If all node's parents have the same type then you can use that approach:
trait BaseNode {
type Parent: BaseNode;
fn parents(&self) -> &[Self::Parent];
}
trait TypedNode<P: BaseNode>: BaseNode<Parent = P> {
type ValueType;
fn value(&self) -> &Self::ValueType;
}
Rust playground
I'm not sure if I understand your question. Please let me know if it doesn't work for you.

Wrapping a Rust struct in a C++ class

I would like to wrap a Rust struct in a C++ class.
Rust:
#[repr(C)]
pub struct RustStruct {
num: i32,
// other members..
}
pub extern "C" fn update(rust_struct: *mut RustStruct) {
(*rust_struct).num = 1i32;
}
extern "C" {
void update(void*);
}
C++:
class Wrapper {
public:
Wrapper();
// ..
private:
void* rustStruct;
// ..
};
Wrapper::Wrapper() {
update(rustStruct); // crash
}
int main() {
std::cout << "Testing..";
}
I understand why this wouldn't work. My question is: how can I achieve what I'm basically trying to do (wrap a rust struct in a c++ class)?
There is a mix of multiple FFIs concepts in your answer, so first let me recommend that your read the Reference.
There are two ways to achieve what you wish, you can either:
use a POD struct (Plain Old Data), aka C-compatible struct
use an opaque pointer (void* in C)
Mixing them, as you did, does not make sense.
Which to pick?
Both solutions have advantages and disadvantages, it's basically an expressiveness versus performance trade-off.
On the one hand, opaque pointers are more expressive: they can point to any Rust type. However:
they require dynamic memory allocation
they require being manipulated by Rust functions (so always indirectly from C or C++)
On the other hand, POD struct do not require either of those, but they are limited to only a subset of types expressible in Rust.
How to use a POD?
This is the easiest, actually, so let's start with it!
In Rust:
#[repr(C)]
pub struct RustStruct {
num: i32,
// other members, also PODs!
}
In C++
struct RustStruct {
int32_t num;
// other members, also with Standard Layout
// http://en.cppreference.com/w/cpp/types/is_standard_layout
};
class Wrapper {
public:
private:
RustStruct rustStruct;
};
Note that I just got along with your question stricto censu here, you could actually merge the two in a single C++ class:
class RustStruct {
public:
private:
int32_t num;
// other members, also with Standard Layout
// http://en.cppreference.com/w/cpp/types/is_standard_layout
};
Just avoid virtual methods.
How to use an opaque pointer?
This gets trickier:
Only the Rust code may correctly create/copy/destruct the type
Beware of leaking...
So, we need to implement a lot of functions in Rust:
#![feature(box_raw, box_syntax)]
use std::boxed;
pub struct RustStruct {
num: i32,
// other members, anything goes
}
pub extern "C" fn createRustStruct() -> *mut RustStruct {
boxed::into_raw(box RustStruct::new())
}
pub extern "C" fn destroyRustStruct(o: *mut RustStruct) {
boxed::from_raw(o);
}
Alright... now on to C++:
struct RustStruct;
RustStruct* createRustStruct();
void destroyRustStruct(RustStruct*);
class Wrapper {
public:
Wrapper(): rustStruct(RustStructPtr(createRustStruct())) {}
private:
struct Deleter {
void operator()(RustStruct* rs) const {
destroyRustStruct(rs);
}
};
typedef std::unique_ptr<RustStruct, Deleter> RustStructPtr;
RustStructPtr rustStruct;
}; // class Wrapper
So, yes, a bit more involved, and Wrapper is not copyable either (copy has to be delegated to Rust too). Anyway, this should get you started!
Note: if you have a lot of opaque pointers to wrap, a templated C++ class taking the copy/destroy functions as template parameters could alleviate a lot of boiler plate.

Tyedef Struct Not Handling Non-Managed C++/CLI

I want to create a picture structure where some of the atributes will be the path to the picture and a bitmap of the picture. The issue is that when I add these atributes it underlines the variable name in red and says
A member of a non-managed class cannot be handled.
Is there some type of workaround for this? Here is my code:
typedef struct{
System::String^ Path;
BitMap^ image;
}Picture
I know I could use a char* for the path, but for other reasons I am choosing to use a String^.
You can't directly embed a managed reference into a native type.
You wrap them into the gcroot template:
typedef struct{
gcroot<System::String^> Path;
gcroot<BitMap^> image;
}Picture
It doesn't work because your typedef declares a native struct (and why are you using typedef struct in C++ in the first place? struct Whatever works just as well, but that's neither here nor there.)
ref struct MyStruct {}
Declares a managed struct, though it's not the same as a C# struct. You can also use:
value struct MyStruct {}
// or
value class MyStruct {}
For a C# equivalent. The struct/class difference in a C++/CLI program are akin to C++ struct/class differences, not C# struct/class differences. It's the ref and value modifiers that are important.

Resources