Parameter passing bug in Boost.Log - c++

I've been experimenting with Boost.Log for the first time and quickly ran into problems. The following simple code does not work correctly for me
#include <boost/log/common.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/sources/logger.hpp>
namespace logging = boost::log;
namespace src = boost::log::sources;
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger)
static void init()
{
logging::add_file_log("test.log");
}
int main(int, char* [])
{
init();
BOOST_LOG(my_logger::get()) << "hello, world";
return 0;
}
The problem is that the log is saved in a file called 00000.log instead of the test.log requested. Investigating a little it seems the problem is that the "test.log" argument isn't being passed down to Boost.Log's internal classes and when this happens a default file pattern of "%N.log" is used which results in the 00000.log file name that I see.
Boost.Log uses Boost.Parameter to implement named parameters so I tried the being explicit about the parameter I'm using
logging::add_file_log(logging::keywords::file_name = "test.log");
This fails in the same way. Interestingly however if I pass two parameters the code works correctly, e.g.
logging::add_file_log(logging::keywords::file_name = "test.log",
logging::keywords::auto_flush = true);
I've not been able to determine where the fault lies, it could be Boost.Log, Boost.Parameter, or a compiler bug. What I'm looking for is some explanation of the nature of the bug. I can work around this particular issue as shown above, but if there's something fundamentally wrong with parameter passing in Boost.Log that's pretty serious. If anyone has any experience with this bug or if they could try the above code on their platform I'd appreciate it.
I'm using Boost 1.74.0 and Visual Studio 2019 and C++17. I'm using static Boost libraries which are linked statically with the C++ runtime.

You're exactly right. It is a bug.
Reducing it all the way:
std::cerr << (kw::file_name = "first.log")[kw::file_name | boost::filesystem::path()] << std::endl;
Prints "". A slightly more informative test-bed:
Live On Coliru
#include <boost/log/utility/setup/file.hpp>
#include <iostream>
int main() {
namespace kw = boost::log::keywords;
auto test = [](auto params) {
std::cerr << "Non-defaulted: " << params[kw::file_name] << std::endl;
std::cerr << "Defaulted: " << params[kw::file_name | boost::filesystem::path()] << std::endl;
};
test((kw::file_name = "aaa"));
test((kw::file_name = "bbb", kw::auto_flush = false));
test((kw::auto_flush = false, kw::file_name = "ccc"));
}
Prints
Non-defaulted: aaa
Defaulted: ""
Non-defaulted: bbb
Defaulted: bbb
Non-defaulted: ccc
Defaulted: ccc
Clearly, the | filesystem::path() syntax is throwing a wrench. And it only manifests in the single-argument case.
Cause/fix?
The correct flow goes into `arglist::operator[]:
template <typename Default>
inline BOOST_CONSTEXPR reference
operator[](
::boost::parameter::aux::default_r_<key_type,Default> const& d
) const
{
return this->get_default(d, _holds_maybe());
}
Into
// Helpers that handle the case when TaggedArg is empty<T>.
template <typename D>
inline BOOST_CONSTEXPR reference
#if defined(BOOST_PARAMETER_CAN_USE_MP11)
get_default(D const&, ::boost::mp11::mp_false) const
#else
get_default(D const&, ::boost::mpl::false_) const
#endif
{
return this->arg.get_value();
}
Into `tagged_arg::
inline BOOST_CONSTEXPR reference get_value() const
{
return this->value;
}
The malfunctioning case goes into
template <typename KW, typename Default>
inline BOOST_CONSTEXPR Default&&
operator[](
::boost::parameter::aux::default_r_<KW,Default> const& x
) const
{
return ::std::forward<Default>(x.value);
}
This is at once incorrect as KW == boost::log::v2_mt_posix::keywords::tag::file_name, so one would have expected this overload to have been taken:
template <typename Default>
inline BOOST_CONSTEXPR reference
operator[](
::boost::parameter::aux::default_r_<key_type,Default> const&
) const
{
return this->get_value();
}
But. That's only defined for tagged_argument_rref, looks like that was an oversight (the overloads for default_<> are both there, for comparison).
Checking The Hypothesis
If the problem is specific for default_r_<> then it should be gone with a default value that is an lvalue:
auto args = (kw::file_name = "aaa");
path lvalue;
std::cerr << "default_r_<>: " << args[kw::file_name | path()] << "\n";
std::cerr << "default_<>: " << args[kw::file_name | lvalue] << "\n";
Which indeed prints
default_r_<>: ""
default_<>: aaa
Fix
It stands to reason that the overload for default_r_<keyword_type, ...> needs to be added for tagged_argument. Indeed this works (on my machine).
I was going to create a PR, so I opened issue #104. But when forking is turns out that there is already a fix in develop:
tree fff523c8fe0a3de1c1378a2292840f217cc4d6d3
parent 0f548424a5f966fadfa7a21a759c835729cbc009
author Andrey Semashev <andrey.semashev#gmail.com> Sun Mar 15 18:13:07 2020 +0300
committer Andrey Semashev <andrey.semashev#gmail.com> Sun Mar 15 18:20:34 2020 +0300
Fix argument value selection with an rvalue default.
In C++11 mode, when named parameter pack was a single tagged argument,
parameter value was not extracted when an rvalue default value was
provided by the user (instead, the default value was returned). This
commit adds a missing overload for default_r_, which returns the parameter
value.
Fixes https://github.com/boostorg/parameter/issues/97.
So, yeah look like the fix is months old and the issue duplicates #97.

Related

Retrieve the name of the pointed-to function from a function pointer template argument at compile time [duplicate]

I have a function wrapper class im trying to work on.
I want to be able to show the name of the function that is passed into the template.
template<auto Func>
struct FuncWrapper final {
FuncWrapper() {
StrFuncName = typeid(Func).name();
std::cout << StrFuncName << std::endl;
}
template<typename... Args>
auto operator()(Args&&... args) const { }
std::string StrFuncName;
};
void Function() { }
FuncWrapper<Function> wrapper;
This is not possible with standard C++. Demangling the typeid won't help either because you're only going to get the name of the type of the function, not the name you actually gave the function.
The closest you can get is the predefined __func__ constant, but that only exists inside the scope of the function you'd want to get the name of anyways.
void foo()
{
std::cout << __func__; // will print "foo"
}
It's not possible in standard C++, but some compiler/libraries may have a way to work around that.
For example, gcc's libstdc++ has an extension which could demangle a typeid value:
#include <cxxabi.h>
std::cout << typeid(type).name() << " -> " abi::__cxa_demangle(typeid(type).name(), 0, 0, 0) << std::endl
It is possible to implement a version of this portably using typeid:
template<auto&>
struct symbol;
template<auto &S>
const char* name() {return typeid(symbol<S>).name();}
The name is of course *implementation-defined; in practice, it may or may not require demangling (in addition to stripping the symbol<…> decoration).
There is the alternative approach of using commonplace compiler extensions:
template<auto &S>
const char* name() {return __PRETTY_FUNCTION__;}
This too has to have the const char * name<…>() stripped.
Getting a function’s name from a non-constant-expression pointer to it is also possible but only via the use of a library that interprets the symbol table and/or debugging information.

Place setw() as a variable

I have this sample block of code:
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(){
string blank = " ";
cout << "Hello" << blank << "47";
}
I have a lot of cout's of this type in my original code.
I want to be able to change the blank string to setw(2) function without having to replace blank with setw(2) on each and every cout I have in my code.
So is there a way to set a cpp function to a variable?
So I can call the function by typing the name?
for example:
func blank = setw(2);
cout<< "Hello" << blank << "47";
The type of std::setw(x) is unspecified, but you don't need to know it.
You can just use auto:
auto blank = std::setw(2);
As #StoryTeller noted, while this should work on sane implementations, it's not guaranteed to.
A safer option would be to make a class with overloaded <<:
struct blank_t {} blank;
std::ostream &operator<<(std::ostream &s, blank_t)
{
return s << std::setw(2);
}
std::setw is a manipulator. Its type is unspecified and implementation specific.
So is there a way to set a cpp function to a variable?
With C++11 you can use function objects, notably std::function. And you also have lambda expressions.
I am not sure you want to use it in your case.
So learn to use your source code editor. Replace every occurrence of blank with the appropriate stuff, that is std::setw(2) .... That makes your code more readable. Good editors are able to do that easily.
You could abuse the preprocessor, and have
#define blank setw(2)
but in your case that is a bad idea (because the code remains unreadable). Even using auto as answered by HolyBlackCat keeps your code unreadable and confusing.
Code is much more often read than written. Keep it readable (even by yourself, in a few weeks).
If you have a huge (million-line) project, spend perhaps a few minutes to write some script to change your source code in such case. BTW, with GNU emacs it is easy (since emacs is a scriptable editor).
An alternative solution is to write a small wrapper class whose only purpose is to provide an overloaded operator<< for an encapsulated referenced object. You can templatise that class so it works with everything that you could feed to an std::ostream in the first place.
Here is an example:
#include <iostream>
#include <iomanip>
#include <string>
template <class T>
struct Blank {
Blank(T const& t) : t(t) {}
T const& t;
};
// utility function so that you can use type deduction at the call site:
template <class T>
Blank<T> blank(T const& t) {
return Blank<T>(t);
}
template <class T>
std::ostream& operator<<(std::ostream& os, Blank<T> const& blank) {
os << std::setw(2) << blank.t;
return os;
}
int main() {
std::cout << "Hello" << blank("4") << blank(7) << blank(std::string("8")) << '\n';
}
It's not exactly the syntax you've asked for, but it comes pretty close.
You also have to make sure that no encapsulated object is destroyed before it's used in operator<< (because then you'd have undefined behaviour due to a dangling reference), but that's easy to accomplish if never create named Blank objects.

Creating a function alias

EDIT: This question was originally titled "Using std::bind to create inline function," but that's not really what I'm after: I just want a simple way to alias functions.
I would like to expose std::chrono::high_resolution_clock::now as a standalone function. That is, I would like to do the following:
auto current_time = std::bind(std::chrono::high_resolution_clock::now);
Unfortunately, since this is in a header file, it results in multiple definitions of current_time at link-time. Is there a way to return an inline function from std::bind?
Here's what I do if I want to create a simple function alias
constexpr auto &&now = std::chrono::high_resolution_clock::now;
and if I want to create a full wrapper alias that will be inlined
template<typename ... Args>
inline constexpr auto now(Args &&... args) -> decltype(std::chrono::high_resolution_clock::now(std::forward<Args>(args)...)){
return std::chrono::high_resolution_clock::now(std::forward<Args>(args)...);
}
The reason why I use a universal reference auto&& in the alias definition is because of the possibility of addressof(now) == addressof(std::chrono::high_resolution_clock::now).
On my system with G++ 4.9.2 running this:
constexpr auto &&now_ref = std::chrono::high_resolution_clock::now;
constexpr auto now_var = std::chrono::high_resolution_clock::now;
template<typename ... Args>
inline constexpr auto now_wrapper(Args &&... args)
-> decltype(std::chrono::high_resolution_clock::now(std::forward<Args>(args)...)){
return std::chrono::high_resolution_clock::now(std::forward<Args>(args)...);
}
int main(int argc, char *argv[]){
std::cout << std::hex << std::showbase;
std::cout << (uintptr_t)std::addressof(std::chrono::high_resolution_clock::now) << '\n';
std::cout << (uintptr_t)std::addressof(now_wrapper<>) << '\n';
std::cout << (uintptr_t)std::addressof(now_var) << '\n';
std::cout << (uintptr_t)std::addressof(now_ref) << '\n';
}
I get the following results:
0x4007c0
0x400a50
0x400ae8
0x4007c0
Showing that only the auto&& is actually a direct alias of the function, whereas all other methods have some level of indirection. (although, after compilation they may be replaced by inlined function calls. maybe.)
I don't think there is anyway to do this as bind is not constexpr.
Also lambdas are not constexpr-able.
Edit: there is this trick to make a constexpr-like lambda http://pfultz2.com/blog/2014/09/02/static-lambda/
Adding another answer 'cause it takes a very different tack to what you want.
std::bind isn't necessary in this case, because no 'binding' is happening.
However I feel this could lead to some confusing problems down the line, since current_time isn't really an alias in the same way that using delcarations are.
#include <iostream>
#include <chrono>
using namespace std;
auto constexpr current_time = std::chrono::high_resolution_clock::now;
int main() {
auto now = current_time();
cout << std::chrono::system_clock::to_time_t(now) << endl;
return 0;
}
Using GCC it is possible to create a "function alias", but only for functions which are defined in the same translation unit and for which you know the mangled name, so it's not possible to do reliably for std::chrono::high_resolution_clock::now()
See the alias attribute at https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
Keep it simple.
const auto current_time = std::chrono::high_resolution_clock::now;

destructor called before temporary should be out of scope

I have a bit of code which fails under VS2015, but works under GCC. I'm pretty sure the bug is with Visual Studio but want to be sure that my understanding of decltype(auto) is correct.
#include <iostream>
using namespace std;
string zero_params()
{
return "zero_params called.";
}
template< typename F >
auto test1( F f ) -> decltype(auto)
{
return f();
}
int main() {
cout << std::is_rvalue_reference< decltype(test1(zero_params)) >::value << endl;
cout << test1(zero_params) << endl;
cout << "Done!" << endl;
return 0;
}
Under Visual Studio the string returned by zero_params is deduced to be an rvalue reference. Furthermore the destructor of that object is called inside test1() where the return from the call to f happens (which seems a reasonable place to destruct a && object).
Under GCC the string returned is not deduced to be an rvalue reference. The destructor is called after use in the cout statement as I'd expect.
Specifying the return type to be 'string' instead of decltype(auto) under Visual Studio fixes it, as does using remove_reference_t on the return of f() inside test1.
My expectation would be that GCC is correct as the function signature for zero_params() is string, not string&& so I would expect the non-reference to 'bubble up' to the return type of test1 if it uses decltype(auto).
Is this a correct assessment?
LATE EDIT:
Another way I've found to get around this with VS2015 is to wrap the function given to test1 in a lambda:
cout << test1(zero_params) << endl;
to:
cout << test1( [](auto&&... ps) { return zero_params(std::forward<decltype(ps)>(ps)...); } ) << endl;
So based on the comments we can conclude:
This is a bug in VS2015 preview
There are workarounds
The bug has been reported
The bug is that:
The compiler should have deduced the return type to be string
It actually deduced it to be string &&
Thus it destroyed the value prematurely
The workarounds are:
Don't use decltype(auto) for the function's return type
Wrap the function in a lambda expression before passing it in

How do I specify default non-template argument initializers in a c++ function template?

EDIT: See my own answer to this question for details. It turns out to be an Eclipse Juno bug, not a C++ problem. Nonetheless, the question still covers a useful topic for other C++ template users.
If I wish to create a template class with an argument of "template" type and other arguments of "non-temlate" types, may I.how do I specify this?
Example: An implementation or itoa() but with multiple types, padding and returning a string...
EDIT: fixed var names in definition.
template <typename T> std::string Num2Str( T x, char pad = ' ', int width = 0 );
template <typename T> std::string Num2Str( T x, char pad, int width )
{
static std::string string;
std::stringstream ss;
ss << std::setfill(pad) << std::setw(width) << x;
string = ss.str();
return string;
}
EDIT: This should work across compilers/platforms, g++, VC++.
I think you're mixing up template params and function params. Why not just this:
#include <sstream>
#include <iomanip>
template <typename T>
std::string Num2Str( T x, char pad = ' ', int width = 0 )
{
static std::string string;
std::stringstream ss;
ss << std::setfill(pad) << std::setw(width) << x;
string = ss.str();
return string;
}
void Test()
{
auto s1 = Num2Str( 1.0 );
auto s2 = Num2Str( 2, '-' );
auto s3 = Num2Str( 3.0, ' ', 3 );
}
Well, I found the bug. Absolutely nothing to so with the syntax or the C++. It's a bug in Eclipse Juno. The indexer doesn't seem to keep up with the build. Rebuilding the index got rid of both bugs. Project Expolrer->(projname)->Index->Rebuild. You may first need to do a Project Expolrer->(projname)->Index->Freshen All Files. Finally, in the Problems pane, ctrl-A to select all the errors then del and ENTER to clear the error log.
The interesting artifact of this indexer bug is that the IDE doesn't always forget the errors it knew about before the current build. It couldn't seem to forget the aforementioned two errors and reported them even though they weren't there!
I'm going to edit the OP to add "Ecipse Juno" as a tag hoping it'll help someone from that group.
Thanks for all the help!