Problem with Formatting User-defined Types with fmt library - fmt

I faced a problem for formatting a user-defined type and ended up with this simple example based on fmt documentation.
struct point_double {
double x, y;
operator const char*() const {
return nullptr;
}
};
namespace fmt {
template <>
struct formatter<point_double> {
template <typename ParseContext>
constexpr auto parse(ParseContext& ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const point_double& p, FormatContext& ctx) {
return format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y);
}
};
} // namespace fmt
void foo() {
point_double p = {1, 2};
fmt::print("{}\n", p);
}
Calling foo will crash because the user-defined formatter is not used. Instead fmt::print will use the default string formatter and crash as the operator returns nullptr.
Is there a way to go around this issue? I'm using fmt 5.3.0

You cannot have both an implicit conversion to const char* and a formatter specialization ({fmt} will now give you a compile-time error), because const char* is already formattable. If you have control over point_double, an easy solution is to make the conversion operator explicit which is a good idea in general. Otherwise you can wrap point_double in another type and provide a formatter specialization for that.

Related

function template specialization for variadic templated function (printf)

I have some Arduino C++11 code that I'm trying to improve: trying to make a printf-like function treat String specially so I don't have to call c_str() myself everywhere I use it. Basically for any builtin type like int float bool etc, I just want to pass the arg as-is, and for String, pass return the c_str(). Hit some snags so I tried this in some of the online compilers available. Starting point is this, using std::string instead of String:
#include <string>
class SerialOut {
public:
template<class ...Ts>
static void error(const char* msg, Ts... args) {
printf(msg, args...);
}
};
int main() {
std::string greeting("hi");
SerialOut::error("Message %d %s\n", 1, greeting.c_str());
}
So I tried creating a function template that just returns the value it gets, with a specialization for std::string:
#include <string>
template <typename T, typename R=T> R raw(T& x) {return x;}
template <> const char* raw<>(std::string& x) {return x.c_str();}
class SerialOut {
public:
template<class ...Ts>
static void error(const char* msg, Ts... args) {
printf(msg, raw(args)...);
}
};
int main() {
std::string greeting("hi");
SerialOut::error("Message %d %s\n", 1, greeting);
}
I get a compilation error when I run this in https://repl.it/languages/cpp11:
clang version 7.0.0-3~ubuntu0.18.04.1 (tags/RELEASE_700/final)
 clang++-7 -pthread -std=c++11 -o main main.cpp
main.cpp:10:25: error: cannot pass object of non-trivial type
'std::__cxx11::basic_string<char>' through variadic function; call will abort at
runtime [-Wnon-pod-varargs]
printf(msg, raw(args)...);
^
main.cpp:16:20: note: in instantiation of function template specialization
'SerialOut::error<int, std::__cxx11::basic_string<char> >' requested here
SerialOut::error("Message %d %s\n", 1, greeting);
^
1 error generated.
compiler exit status 1
With https://www.onlinegdb.com/online_c++_compiler there is no error but the raw() specialization is not selected, so the output for greeting is garbage.
In Arduino IDE I get a slightly different error (after replacing std::string by String, of course):
sketch\mqtt.cpp.o: In function `char const* raw<String, char const*>(String&)':
sketch/utils.h:15: multiple definition of `char const* raw<String, char const*>(String&)'
sketch\Thermistor.cpp.o:sketch/utils.h:15: first defined here
sketch\sketch.ino.cpp.o: In function `char const* raw<String, char const*>(String&)':
sketch/utils.h:15: multiple definition of `char const* raw<String, char const*>(String&)'
sketch\Thermistor.cpp.o:sketch/utils.h:15: first defined here
I tried several variations on the raw() functions, to no avail. I figure I'm just missing a subtlety or it's just not possible to do this in C++11.
Update: I found Variadic Macro: cannot pass objects of non-trivially-copyable type through '...', one of the answers solves the above in C++14 (basically use decltype(auto) and overload instead of specialization). I added a slight variation on it that works also in C++11, and with "inline" it also works in Arduino C++ (without "inline" on the overload, the above message about multiple definitions -- turns out this is a linker message so it does compile, I guess the Arduino variant doesn't inline "obviously inlined" functions as other compilers).
Something along these lines, perhaps:
template <typename T>
struct SerialHelper {
static T raw(T val) { return val; }
};
template <>
struct SerialHelper<std::string> {
static const char* raw(const std::string& val) { return val.c_str(); }
};
class SerialOut {
public:
template<class ...Ts>
static void error(const char* msg, Ts... args) {
printf(msg, SerialHelper<Ts>::raw(args)...);
}
};
Demo
Based on Variadic Macro: cannot pass objects of non-trivially-copyable type through '...' I got it to work with this very simple change, which works in C++11 and Arduino C++:
#include <string>
template <typename T> T raw(const T& x) {return x;}
inline const char* raw(const String& x) {return x.c_str();}
class SerialOut {
public:
template<class ...Ts>
static void error(const char* msg, Ts... args) {
printf(msg, raw(args)...);
}
};
int main() {
std::string greeting("hi");
SerialOut::error("Message %d %s\n", 1, greeting);
}
Thanks to #IgorTandetnik comment, it is clear why.

Converting all variadic arguments into a single std::string via move semantics

I have a class that contains a lambda function that looks like this:
class Foo {
private:
inline static std::string text{};
public:
template<typename...T>
inline static auto func = [](T&&...args) mutable throw() {
text += std::string(args...);
};
void show() {
std::cout << text << '\n';
}
};
My intended use would be something like this:
int main() {
Foo bar;
bar.func<std::string, int, std::string>( "Hello, I am", 39, "years old!");
bar.show();
return 0;
}
I want the templated variadic lambda to take in any type of parameter that is a basic type such as string, char*, char[], int, float, double, etc... and to convert all of them into a single std::string that will be stored within the class.
When I run my code as such:
int main() {
Foo bar;
bar.func<string>( "Hello world!");
bar.show();
return 0;
}
Everything compiles fine, however, when I begin to add in various types such as the example from the intended use above, it fails to compile. Microsoft Visual Studio is giving me a C2400 compiler error: cannot convert from initialize list to std::string. No constructor could take the source type, or constructor overload resolution was ambiguous...
I believe I understand why it is ambiguous as that's not so much the issue. My question is what would be the proper and efficient way of using "move semantics or perfect forwarding"? I'm trying to avoid a bunch of copies of temporaries.
You could use fold expressions:
template<typename...T>
inline static auto func = [](T&&...args) mutable throw() {
text += (toString(args) + ...);
};
where toString is defined as:
template<class T>
std::string toString(T&& t){
if constexpr (std::is_arithmetic_v<std::decay_t<T>>)
return std::to_string(std::forward<T>(t));
else
return std::forward<T>(t);
}
you can extend toString to handle all types you need to convert to string.
Demo

Specialising templates on C++AMP restricted lambdas

Using the insight of this question (and a few others) I have been able to write the following for interrogating normal lambda function type infromation (i.e. return type, argument count etc)
// helper classes ========================================
template <typename R, typename... A>
class lambda_traits_evaluation {
public:
typedef R r_type;
enum { n_args = sizeof...(A) };
// ...
};
template <typename R, typename... A>
class lambda_traits_helper
: public lambda_traits_evaluation<R,A...>{};
template <typename R, typename F, typename... A>
class lambda_traits_helper<R (F::*)(A...) const>
: public lambda_traits_evaluation<R,A...>{};
// use class ========================================
template <typename F>
class lambda_traits {
typedef typename lambda_traits_helper<decltype(&F::operator())> helper_impl;
// ...
}
I can then use this with lambda_traits<decltype(myLambda)> but that is where my smug coding ends because if my lambda is amp restricted for the gpu i.e.
auto myLambda = [](int) restrict(amp) -> void {};
as obviously the template specialisation is not picked up. However adding the new specialisation
template <typename R, typename F, typename... A>
class lambda_traits_helper<R (F::*)(A...) const restrict(amp)>
: public lambda_traits_evaluation<R,A...> {};
still does not solve the problem as I discover that the compiler barks
error C3939: 'abstract declarator' : pointer to member functions, function
pointers, references to functions with 'amp' restriction
specifier are not allowed
is there another way to interrogate the types in lambdas or else a way to strip the restrict off the lambda type?
The inability to form a pointer to an amp-restricted function, even in unevaluated context, is a bummer. There is however a workaround, which is viable as long as you can require the amp-restricted lambdas to be cpu,amp-restricted. In such case you can cast-away the amp-restriction, forming a pointer to the cpu-restricted member function -- which you can interrogate further.
See the following proof-of-concept:
#include <type_traits>
template <typename R, typename F, typename... A>
auto get_R(R (F::*)(A...) const) -> R
{}
template <typename L>
struct lambda_traits
{
using ret_type = decltype(get_R(&L::operator()));
};
int main()
{
auto lambda_1 = [](int) restrict(cpu,amp) -> void {};
auto lambda_2 = [](int) restrict(cpu,amp) -> int { return 0; };
// Test:
static_assert(std::is_same<lambda_traits<decltype(lambda_1)>::ret_type, void>::value, "Failed 1.");
static_assert(std::is_same<lambda_traits<decltype(lambda_2)>::ret_type, int>::value, "Failed 2.");
}
Hope that helps!

Can't invoke or assign a std::function that has an rvalue reference as an argument (Visual C++)

Seems like Visual C++'s std::function<> doesn't handle functions with rvalue refs as arguments. Can anyone suggest a workaround?
#include <functional>
using namespace std;
class Object { };
void f(Object&&) { }
auto g = [](Object&&){ };
function<void(Object&&)> h;
int main()
{
Object o;
f(move(o));
g(move(o));
// Uncomment any one of the following lines, and we get an error from the instantiation
// of std::function: "error C2664: You cannot bind an lvalue to an rvalue reference"
//h(move(o));
//h = g;
//h = f;
return 0;
}
This is Visual Studio 2010. I am not using /Za (so it is not this problem).
Update after some research: The code compiles in Clang, so I am pretty sure it is a Microsoft bug. It might be this one, fixed in VC11: 649274
Correction to the update: The MS bug is not fixed in VC11. From the link:
our first opportunity will be the "out of band" release between VC11 and VC12 that Herb Sutter
announced at the GoingNative 2012 conference.
I'm not sure what workaround you'd like here. Assuming you cannot change the call expression of the function object and the target signature, you can wrap the rvalue reference and pass the wrapped object (a temporary) via const ref.
Essentially, the call expands to: f( wrap(move(o)) );
I suspect there's a problem with perfect forwarding, because binding i = bind(&f); does not work; therefore I've introduced an intermediate step performing perfect forwarding, such that the call is resolved to: f( move( (Object&)wrap( move(o) ) ) );
#include <iostream>
#include <functional>
using namespace std;
struct Object { int m; };
// target function with fixed signature (assuming we cannot change that)
void f(Object&& p) { p.m = 42; std::cout << p.m; };
// was surprised I didn't find any method to chain functions in the StdLib
// so here's my own:
template < typename F1, typename F2, typename P1 >
auto chain2(F1 f1, F2 f2, P1&& p1)
-> decltype( f1(f2( std::forward<P1>(p1) )) )
{
return f1( f2( std::forward<P1>(p1) ) );
}
// a special bind version; mostly syntactic sugar
// note you can also deduce the first template parameter; would be more work
// and not necessary here
template < typename P1, typename F1, typename F2 >
auto bind_chain(F1 f1, F2 f2)
-> decltype( std::bind( &chain2<F1,F2,P1>, f1, f2, std::placeholders::_1 ) )
{
return std::bind( &chain2<F1,F2,P1>, f1, f2, std::placeholders::_1 );
}
// as `std::move` is overloaded, we make things a little bit simpler;
// we later will need to get a function pointer on this, that's why
// I'd like to avoid too much overloading
template < typename T >
// for a certain reason, cannot use && here --------v, clang++3.2 accepts it
typename std::remove_reference<T>::type && my_move(T& p)
{
return std::move(p);
}
struct wrapper
{
Object&& m;
wrapper(Object&& p) : m(std::move(p)) {}
operator Object&() const { return m; }
// alternatively:
// operator Object&&() const { return std::move(m); }
};
int main()
{
Object o;
// we'll need to call the functor with an const ref
function<void(wrapper const&)> i;
// chaining the conversion to rvalue ref with the target function
i = bind_chain<wrapper const&>( &f, &my_move<Object> );
i( move(o) );
return 0;
}

How do I pass a struct by reference in WinRT Component C++/CX

I have the following in my WinRT component:
public value struct WinRTStruct
{
int x;
int y;
};
public ref class WinRTComponent sealed
{
public:
WinRTComponent();
int TestPointerParam(WinRTStruct * wintRTStruct);
};
int WinRTComponent::TestPointerParam(WinRTStruct * wintRTStruct)
{
wintRTStruct->y = wintRTStruct->y + 100;
return wintRTStruct->x;
}
But, it seems that the value of winRTStruct->y and x are always 0 inside the method, when called from C#:
WinRTComponent comp = new WinRTComponent();
WinRTStruct winRTStruct;
winRTStruct.x = 100;
winRTStruct.y = 200;
comp.TestPointerParam(out winRTStruct);
textBlock8.Text = winRTStruct.y.ToString();
What is the correct way to pass a struct by reference so it an be updated inside the method of a WinRTComponent written in C++/CX?
You cannot pass a struct by reference. All value types (including structs) in winrt are passed by value. Winrt structs are expected to be relatively small - they're intended to be used for holding things like Point and Rect.
In your case, you've indicated that the struct is an "out" parameter - an "out" parameter is write-only, its contents are ignored on input and are copied out on return. If you want a structure to be in and out, split it into two parameters - one "in" parameter and another "out" parameter (in/out parameters are not allowed in WinRT because they don't project to JS the way you expect them to project).
My co-worker helped me solve this.
In WinRT components, it seems that the best way to do this is to define a ref struct instead of a value struct:
public ref struct WinRTStruct2 sealed
{
private: int _x;
public:
property int X
{
int get(){ return _x; }
void set(int value){ _x = value; }
}
private: int _y;
public:
property int Y
{
int get(){ return _y; }
void set(int value){ _y = value; }
}
};
But this creates other problems. Now the VS11 compiler gives INTERNAL COMPILER ERROR when I try to add a method to the ref struct that returns an instance of the struct.

Resources