The problem
I am implementing a class where I want to let the user choose the string type (std::string, std::wstring, std::u16string, ...) via a template parameter. I currently fail to make the string literals fit the chosen string type: Once I decide for a literal prefix ("hello" vs. L"hello" vs. u"hello" vs. U"hello"), I get compilation errors for all incompatible string classes.
Toy example
As an example, consider the following code (compile with --std=c++11):
#include <string>
template<typename StringType>
void hello_string()
{
StringType result("hello");
}
int main()
{
// works
hello_string<std::string>();
hello_string<std::basic_string<char>>();
// the code below does not compile
hello_string<std::wstring>();
hello_string<std::basic_string<unsigned char>>();
hello_string<std::u16string>();
}
Function hello_string() shows the essence of what I want to do: have a string type as template parameter, and assign string literals to variables of this type.
Possible workaround
One way to overcome my problem would be to implement several specializations of the hello_string() function. The problem is that this would lead to several copies of each string literal - one for each string literal prefix. I think this is rather ugly, and there must be better way.
Another way could be to chose "normal" string literals as default values and have functions do a conversion to the different string types. While this would avoid code duplication, it would introduce unnecessary conversions of something that is actually constant.
You can make yourself a macro. First define a struct that wraps the char-choosing:
namespace details {
template<typename T>
struct templ_text;
template<>
struct templ_text <char>
{
typedef char char_type;
static const char_type * choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return narrow; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return narrow; }
};
template<>
struct templ_text < wchar_t >
{
typedef wchar_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return wide; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return wide; }
};
template<>
struct templ_text < char16_t >
{
typedef char16_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u16; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u16; }
};
template<>
struct templ_text < char32_t >
{
typedef char32_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u32; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u32; }
};
}
Wrap it into a nice macro:
#define TEMPL_TEXT(Ch, txt) details::templ_text<Ch>::choose(txt, L##txt, u##txt, U##txt)
Then your function would be:
template<typename StringType>
void hello_string()
{
StringType result(TEMPL_TEXT(typename StringType::value_type, "Hello"));
}
I think that unused copies of the string will be optimized away.
Related
I've been diving into FFI with Rust, and while there are some useful posts and documentation on passing in strings and sometimes getting a string back as the return value from a C function, I don't see any way to get an out parameter. To get my feet wet, I am trying to access a C library that exposes a function that is declared as:
unsigned char *some_func(
const unsigned char *key,
unsigned int klen,
const unsigned char *src,
unsigned char *dest,
unsigned int slen);
I think it should be declared roughly as:
use libc;
extern "C" {
fn some_func(
key: *const libc::c_uchar,
klen: libc::c_uint,
src: *const libc::c_uchar,
dest: *mut libc::c_uchar,
slen: libc::c_uint) -> *mut libc::c_uchar;
}
// wrapper
pub fn wrapped_func(key: &str, src: &str) -> String {
unsafe {
let key_len = key.len() as u32;
let key = std::ffi::CString::new(key).unwrap();
let src_len = src.len() as u32;
let src = std::ffi::CString::new(src).unwrap();
let key_ptr = key.as_ptr();
let src_ptr = src.as_ptr();
let mut dest: *mut std::ffi::CStr;
let result = PC1(key_ptr, key_len, src_ptr, &mut dest, src_len);
// ^^^^^^^^^ expected `u8`, found *-ptr
key_ptr = ptr::null();
src_ptr = ptr::null();
let result_string = if let Ok(s) = result.to_str() {
String::from(s)
} else {
String::new()
};
dest = ptr::null();
result_string
}
There are a few issues I'm having with this:
I don't know how to properly declare dest as my out string. What's the right way to get an output string? From Wrapping Unsafe C Libraries in Rust, it looks like I need to treat this as a CStr:
For cases where you’re getting a const char * from a C function and want to convert it to something Rust can use, you’ll need to ensure it’s not null, then convert it into a &CStr with an appropriate lifetime. If you can’t figure out how to express an appropriate lifetime, the safest thing is to immediately convert it into an owned String!
The C code - and therefore my extern function - declares the strings as unsigned char *, but when I try to invoke, I have a type mismatch between u8 and i8. Is it acceptable to just switch the extern to be c_char, or is this dangerous?
Is setting key_ptr = ptr::null() the correct way (and all that's needed) to release the memory safely?
In C++, I want to get value from string.
I know there are functions like stoi, stol, stof...
But can I write a function that includes all of them? like using a template to infer the data type?
template<typename T>
T fromString(const std::string& s){
// do something here
// call stoi, stof according to typename T
}
string si = "1234";
int integer = fromString<int>(si);
string sf = "1234.1234";
float float_point = fromString<float>(sf);
Cannot comment yet, hence this ...
Not clear if you're looking for a single function, or templated (overloaded) functions? This would work: Have no default implementation with return type T, and specializations / usage so:
template<typename T> foo(const std::string& str) {}
template<> int foo(const std::string& str) {return atoi(str.c_str());}
template<> double foo(const std::string& str) {return atof(str.c_str());}
...
const std::string str1("1234"); const std::string str2("12.34");
const auto iVal = foo<int>(str1);
const auto dVal = foo<double>(str2);
Note the absence of specialization in the function name with the template function specialization, of course it appears as a return type.
I use boosts property tree, included via
#include "boost\property_tree\ptree.hpp"
And... I'd like to create a simple function which substitutes a value in case none is found via a fairly straight-forward template function:
template <typename Type>
Type getValueOrDefault( std::string const& str, Type defaultValue )
{
Type returnValue = defaultValue;
try {
returnValue = mSettings.get<Type>( str );
}
catch ( boost::property_tree::ptree_error &e )
{
// Log error!
}
return returnValue;
}
This works well in principle, but runs into a bit problems if I rely on C-style string. For example, calling the function as follows:
getValueOrDefault( "pathToImportantStuffParameter", "c:/defaultdir/" )
will result in the following error:
boost\property_tree\stream_translator.hpp(36): error C2678: binary '>>' : no operator found which takes a left-hand operand of type 'std::basic_istream<char,std::char_traits<char>>' (or there is no acceptable conversion)
The error stems from passing char const * as a template parameter which makes a fair bit of sense. Two obvious solutions to this issue would be to force the default value to be a std::string object, like so:
getValueOrDefault<std::string>( "pathToImportantStuffParameter", "c:/defaultdir/" )
getValueOrDefault( "pathToImportantStuffParameter", std::string("c:/defaultdir/") )
But I'm wondering if someone might know of some template magic I could sprinkle to automatically interpret c-style strings as std::strings?
You can provide a char array overload which converts the char array to a std::string and then calls the default implementation:
#include <iostream>
#include <string>
template <typename T>
T getValueOrDefault(const std::string& str, T&& defaultValue)
{
std::cout << "inside default implementation" << std::endl;
/* ... */
return defaultValue;
}
template <std::size_t N>
std::string getValueOrDefault(const std::string& str, const char (&defaultValue)[N])
{
std::cout << "inside char[] overload" << std::endl;
return getValueOrDefault(str, std::string(defaultValue));
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
return 0;
}
live example
An alternative solution is to use custom type traits:
#include <string>
#include <type_traits>
template <typename T>
struct return_type
{
using type = T;
};
template <>
struct return_type<const char*>
{
using type = std::string;
};
template <typename T>
using return_type_t = typename return_type<typename std::decay<T>::type>::type;
template <typename T>
return_type_t<T> getValueOrDefault(const std::string& str, T&& defaultValue)
{
return_type_t<T> value(defaultValue);
/* ... */
return value;
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
static_assert(std::is_same<decltype(x), std::string>::value, "");
return 0;
}
live example
The only way I found is to specialize getValueOrDefault for const char*, which calls getValueOrDefault with std::string explicitly:
//Note that the return value is unspecified, it returns a 'const char*' to a temporary,
//which will be destroyed when the function returns
template <>
const char* getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue).c_str();
}
If you want to that function to return a std::string instead of an invalid const char*, you have to change the template signature a bit:
//Default return type is the same as paramter
template <typename Type, typename Return = Type>
Return getValueOrDefault(std::string const& str, Type defaultValue)
{
//...
}
//Trick the compiler to select this overload for 'const char*'
template <typename Return = std::string>
Return getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string, std::string>(str, defaultValue);
}
or you could just plain overload the function (thanks #m.s.)
//Overload for 'const char*'
std::string getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue);
}
There is also a third way (if you can use C++14), using the string literal ""s:
//"c:/defaultdir/"s is a std::string (note the s after it => string literal)
getValueOrDefault("pathToImportantStuffParameter", "c:/defaultdir/"s);
I want to have a Rust library expose a const char * static string to C, to be compatible with an existing interface (specifically librsync). That is, the C header file has
extern char const *my_string;
In C, the library would simply have
char const *my_string = "hi";
In Rust I've tried something like
pub static my_string: *const libc::c_char = unsafe { "hi\0" as *const libc::c_char };
but this complains
error: casting `&'static str` as `*const i8` is invalid
It seems like I can't use CString etc because they won't be a compile-time constant expression.
We need a public, static, unmangled pointer to some zero-terminated bytes:
#[export_name = "CONST_C_STR"] // or #[no_mangle]
pub static CONST_C_STR: &[u8; 20] = b"a constant c string\0";
This worked with a simple C program:
#include <stdio.h>
extern char * CONST_C_STR;
int main(int argc, char *argv[]) {
printf("%s\n", CONST_C_STR);
}
The crate c_str_macro provides a convenience macro c_str!, which appends a 0 byte to a Rust string literal and presents it as a CStr reference.
Disclaimer: I'm the author of the crate.
I want to generate a unique id for every type at compile time. Is this possible in Rust?
So far, I have the following code
//Pseudo code
struct ClassTypeId{
id: &'static uint
}
impl ClassTypeId{
fn get_type<T>(&mut self) -> &'static uint {
let _id :&'static uint = self.id + 1;
self.id = _id;
_id
}
}
let c = ClassTypeId{id:0};
c.get_type::<i32>(); // returns 1
c.get_type::<f32>(); // returns 2
c.get_type::<i32>(); // returns 1
c.get_type::<uint>(); // returns 3
I stole this idea from a C++ library, which looks like this
typedef std::size_t TypeId;
template <typename TBase>
class ClassTypeId
{
public:
template <typename T>
static TypeId GetTypeId()
{
static const TypeId id = m_nextTypeId++;
return id;
}
private:
static TypeId m_nextTypeId;
};
template <typename TBase>
TypeId ClassTypeId<TBase>::m_nextTypeId = 0;
}
std::any::TypeId does something like that:
use std::any::TypeId;
fn main() {
let type_id = TypeId::of::<isize>();
println!("{:?}", type_id);
}
outputs:
TypeId { t: 4150853580804116396 }
This sounds like a job for the bitflags! macro:
#[macro_use] extern crate rustc_bitflags;
bitflags!(
#[derive(Debug)]
flags ComponentMask: u8 {
const Render = 0b00000001,
const Position = 0b00000010,
const Physics = 0b00000100
}
);
// the set of components owned by an entity:
let owned_components: = Render | Position;
// check whether an entity has a certain component:
if owned_components.contains(Physics) { ... }
http://doc.rust-lang.org/rustc_bitflags/macro.bitflags!.html
If you want to manage type ids manually, you can use my unique-type-id crate. It allows you to specify what ids a type has in a special file. It will generate them at compile time. Currently it can be used in this way:
use unique_type_id::UniqueTypeId;
#[derive(UniqueTypeId)]
struct Test1;
#[derive(UniqueTypeId)]
struct Test2;
assert_eq!(Test1::id().0, 1u64);
assert_eq!(Test2::id().0, 2u64);
It can both generate types using incremental number and use the id from a file.