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;
Related
I have some code which allow a value to be converted into a string, and this works perfectly in g++ and CLion, however when I try to run the same program with MSVC in Visual Studio the program gives many errors, some of which are syntax errors which is quite odd.
This is the code I am using:
// 1- detecting if std::to_string is valid on T
template<typename T>
using std_to_string_expression = decltype(std::to_string(std::declval<T>()));
template<typename T>
constexpr bool has_std_to_string = is_detected<std_to_string_expression, T>;
// 2- detecting if to_string is valid on T
template<typename T>
using to_string_expression = decltype(to_string(std::declval<T>()));
template<typename T>
constexpr bool has_to_string = is_detected<to_string_expression, T>;
// 3- detecting if T can be sent to an ostringstream
template<typename T>
using ostringstream_expression = decltype(std::declval<std::ostringstream&>() << std::declval<T>());
template<typename T>
constexpr bool has_ostringstream = is_detected<ostringstream_expression, T>;
// -----------------------------------------------------------------------------
// 1- std::to_string is valid on T
template<typename T, typename std::enable_if<has_std_to_string<T>, int>::type = 0>
std::string toString(T const& t) {
return std::to_string(t);
}
// 2- std::to_string is not valid on T, but to_string is
template<typename T, typename std::enable_if<!has_std_to_string<T> && has_to_string<T>, int>::type = 0>
std::string toString(T const& t) {
return to_string(t);
}
// 3- neither std::string nor to_string work on T, let's stream it then
template<typename T, typename std::enable_if<!has_std_to_string<T> && !has_to_string<T> && has_ostringstream<T>, int>::type = 0>
std::string toString(T const& t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
I wonder if I am doing something very obviously wrong, or if there is something a bit more complicated leading to the issue. What do I need to change in order to make this program work in Visual Studio and compile correctly?
std::experimental::is_detected is not supported in Visual Studio 2019 or earlier. You can pretty easily write your own cross platform implementation of it though, as demonstrated here: https://topanswers.xyz/cplusplus?q=1295
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.
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.
Is this a valid c++ syntax?
template<typename Var, typename T>
struct rebindVar;
template<typename Var, typename... T>
struct rebindVar<Var, std::tuple<T...> > {
typedef typename std::tuple< typename T::template rebindVar<Var>::type... > type;
};
Working in gcc, doesn't work in vs2013. The error message says:
Error 1 error C3546: '...' : there are no parameter packs available to expand C:\Users\Alexandros\Desktop\project\tnnlib\src\NeuralNetwork\NeuralNetwork\Perceptron\Perceptron.h 55 1 NeuralNetwork_ut
MSVC's variadic templates implementation is a huge mess, and many slightly more complex expansion patterns don't work. The usual workaround is to extract the complex part into a helper template. Try this:
template <typename Var, typename T>
struct rebindOne { typedef typename T::template rebindVar<Var>::type type; };
template<typename Var, typename... T>
struct rebindVar<Var, std::tuple<T...> > {
typedef typename std::tuple< typename rebindOne<Var, T>::type... > type;
};
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.