I want to split a wstring into a vector<wstring> using a single separator character.
This character is defined in a header file as a single char.
In order to keep the code clean and readable, I would really like to do this on a single line :)
I could not find a predicate to use, so I decided to use a C++11 lambda.
#include <boost/algorithm/string/split.hpp>
#include <vector>
#include <string>
constexpr char separator = '.'; // This is how it's declared in some header file
int main()
{
std::wstring text( L"This.is.a.test" );
std::vector<std::wstring> result;
// can't use is_any_of() unless i convert it to a wstring first.
boost::algorithm::split( result, text, [](wchar_t ch) -> bool { return ch == (wchar_t) separator; });
return 0;
}
Unfortunately, this results in a compilation error (clang 3.3):
clang++ -c -pipe -fPIC -g -std=c++11 -Wextra -Wall -fPIE -DQT_QML_DEBUG -DQT_DECLARATIVE_DEBUG -I/usr/include -I/usr/lib64/qt5/mkspecs/linux-clang -I../splittest -I. -o debug/main.o ../splittest/main.cpp
In file included from ../splittest/main.cpp:1:
In file included from /usr/include/boost/algorithm/string/split.hpp:16:
/usr/include/boost/algorithm/string/iter_find.hpp:148:13: error: non-type template argument refers to function 'failed' that does not have linkage
BOOST_CONCEPT_ASSERT((
^~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/concept/assert.hpp:44:5: note: expanded from macro 'BOOST_CONCEPT_ASSERT'
BOOST_CONCEPT_ASSERT_FN(void(*)ModelInParens)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/concept/detail/general.hpp:70:6: note: expanded from macro 'BOOST_CONCEPT_ASSERT_FN'
&::boost::concepts::requirement_<ModelFnPtr>::failed> \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/algorithm/string/split.hpp:146:40: note: in instantiation of function template specialization 'boost::algorithm::iter_split<std::vector<std::basic_string<wchar_t>, std::allocator<std::basic_string<wchar_t> > >, std::basic_string<wchar_t>, boost::algorithm::detail::token_finderF<<lambda at ../splittest/main.cpp:13:44> > >' requested here
return ::boost::algorithm::iter_split(
^
../splittest/main.cpp:13:23: note: in instantiation of function template specialization 'boost::algorithm::split<std::vector<std::basic_string<wchar_t>, std::allocator<std::basic_string<wchar_t> > >, std::basic_string<wchar_t>, <lambda at ../splittest/main.cpp:13:44> >' requested here
boost::algorithm::split( result, text, [](wchar_t ch) -> bool { return ch == (wchar_t) separator; });
^
/usr/include/boost/concept/detail/general.hpp:46:17: note: non-type template argument refers to function here
static void failed() { ((Model*)0)->constraints(); }
^
1 error generated.
Am I doing something wrong or are C++11-lambdas not (completely?) supported in boost?
Is there another somehow readable single line solution?
I am currently using an own predicate is_char() which I defined in some base library, but I would rather get rid of it.
I know of boost lambdas (haven't used them, yet) - but should they really be used in C++11 code?
Thanks!
Out on a limb, try defining this before including the first boost header (beware of precompiled headers):
#define BOOST_RESULT_OF_USE_DECLTYPE
Or - conversely
#define BOOST_RESULT_OF_USE_TR1
I believe the defaults have changed. Recently. For specific compilers, so this could well explain it.
Related
The following code has been compiled with gcc-5.4.0 with no issues:
% gcc -W -Wall a.c
...
#include <stdio.h>
#include <stdarg.h>
static int debug_flag;
static void debug(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
#define DEBUG(...) \
do { \
if (debug_flag) { \
debug("DEBUG:"__VA_ARGS__); \
} \
} while(0)
int main(void)
{
int dummy = 10;
debug_flag = 1;
DEBUG("debug msg dummy=%d\n", dummy);
return 0;
}
However compiling this with g++ has interesting effects:
% g++ -W -Wall -std=c++11 a.c
a.c: In function ‘int main()’:
a.c:18:10: error: unable to find string literal operator ‘operator""__VA_ARGS__’ with ‘const char [8]’, ‘long unsigned int’ arguments
debug("DEBUG: "__VA_ARGS__); \
% g++ -W -Wall -std=c++0x
<same error>
% g++ -W -Wall -std=c++03
<no errors>
Changing debug("DEBUG:"__VA_ARGS__); to debug("DEBUG:" __VA_ARGS__); i.e. space before __VA_ARGS__ enables to compile with all three -std= options.
What is the reason for such behaviour? Thanks.
Since C++11 there is support for user-defined literals, which are literals, including string literals, immediately (without whitespace) followed by an identifier. A user-defined literal is considered a single preprocessor token. See https://en.cppreference.com/w/cpp/language/user_literal for details on their purpose.
Therefore "DEBUG:"__VA_ARGS__ is a single preprocessor token and it has no special meaning in a macro definition. The correct behavior is to simply place it unchanged into the macro expansion, where it then fails to compile as no user-defined literal operator for a __VA_ARG__ suffix was declared.
So GCC is correct to reject it as C++11 code.
This is one of the backwards-incompatible changes between C++03 and C++11 listed in the appendix of the C++11 standard draft N3337: https://timsong-cpp.github.io/cppwp/n3337/diff.cpp03.lex
Before C++11 the string literal (up to the closing ") would be its own preprocessor token and the following identifier a second preprocessor token, even without whitespace between them.
So GCC is also correct to accept it in C++03 mode. (-std=c++0x is the same as -std=c++11, C++0x was the placeholder name for C++11 when it was still in drafting)
It is also an incompatibility with C (in all revisions up to now) since C doesn't support user-defined literals either and considers the two parts of "DEBUG:"__VA_ARGS__ as two preprocessor tokens as well.
Therefore it is correct for GCC to accept it as C code as well (which is how the gcc command interprets .c files in contrast to g++ which treats them as C++).
To fix this add a whitespace between "DEBUG:" and __VA_ARGS__ as you suggested. That should make it compatible with all C and C++ revisions.
I am working on a project which uses the LLVM YAML I/O library. This is the documentation/tutorial that I am following:
https://www.llvm.org/docs/YamlIO.html
I am trying to replicate the example where you define a specialization on llvm::yaml::MappingTraits for a struct data type. This example is at the top of the page.
This is my code that I have written:
#include <cstdlib> /* for EXIT_FAILURE */
#include <string>
#include <vector>
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLParser.h"
using std::string;
using std::vector;
using llvm::outs;
using llvm::errs;
using llvm::yaml::ScalarEnumerationTraits;
using llvm::yaml::MappingTraits;
using llvm::yaml::IO;
using llvm::yaml::Input;
using llvm::yaml::Output;
struct Person {
string name;
int hatSize;
};
template <>
struct MappingTraits<Person> {
static void mapping(IO& io, Person& info) {
io.mapRequired("name", info.name);
io.mapOptional("hat-size", info.hatSize);
}
};
int main(int argc, const char **argv) {
Person tom;
tom.name = "Tom";
tom.hatSize = 8;
Person dan;
dan.name = "Dan";
dan.hatSize = 7;
std::vector<Person> persons;
persons.push_back(tom);
persons.push_back(dan);
Output yout(llvm::outs());
yout << persons;
return EXIT_SUCCESS;
}
It seems to me that I have replicated the example code that they have in that tutorial exactly. But when I try to compile the program (using makefile) I get this cryptic error message:
clang++ -I/usr/local/include -std=c++11 -fno-exceptions -fno-rtti -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++14 -fcxx-exceptions -g -Wall -c -o yaml_project.o yaml_project.cpp
In file included from yaml_project.cpp:12:
/usr/local/include/llvm/Support/YAMLTraits.h:1871:36: error: implicit instantiation of undefined template 'llvm::yaml::MissingTrait<std::vector<Person, std::allocator<Person> > >'
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
^
yaml_project.cpp:153:10: note: in instantiation of function template specialization 'llvm::yaml::operator<<<std::vector<Person, std::allocator<Person> > >' requested here
yout << persons;
^
/usr/local/include/llvm/Support/YAMLTraits.h:307:8: note: template is declared here
struct MissingTrait;
^
1 error generated.
<builtin>: recipe for target 'yaml_project.o' failed
make: *** [yaml_project.o] Error 1
I don't think that the error is in the command that I am using to compile this program, because it has worked for me before to compile and link the LLVM libraries into my executable. I think that the problem is in the code, but I cannot identify what.
The code for the mentioned header file llvm/Support/YAMLTraits.h is here:
https://llvm.org/doxygen/YAMLTraits_8h_source.html
Reading the documentation, it seems to me that support for your specific vector<Person> requires registration with a macro:
LLVM_YAML_IS_SEQUENCE_VECTOR(Person)
// or
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Person)
See, Utility Macros: https://llvm.org/docs/YamlIO.html#id22
So I want to use a custom type (here, SWrapper) as the key type for an unordered_multimap. I've defined a hash class, derived from the standard hashing function for strings, and included the hashing class in the type of the multimap. Some code that reproduces the error is displayed below. This compiles on Arch Linux with both g++ and clang++, but on MacOS with clang++, I get errors:
#include <unordered_map>
#include <functional>
#include <string>
class SWrapper {
public:
SWrapper() {
(*this).name = "";
}
SWrapper(std::string name) {
(*this).name = name;
}
bool operator==(SWrapper const& other) {
return (*this).name == other.name;
}
std::string name;
};
class SWrapperHasher {
size_t operator()(SWrapper const& sw) const {
return std::hash<std::string>()(sw.name);
}
};
int main(int argc, char* argv[]) {
auto mm = std::unordered_multimap<SWrapper, int, SWrapperHasher>();
return 0;
}
Running g++ -std=c++11 -Wall -Wpedantic -Wextra hash_map_test.cpp -o hash_map_test on Arch Linux (or clang++) compiles the code with no errors. However, on MacOS, using the same command, I get the following error message:
In file included from hash_map_test.cpp:1:
In file included from /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:408:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__hash_table:868:5: error:
static_assert failed due to requirement 'integral_constant<bool, false>::value' "the
specified hash does not meet the Hash requirements"
static_assert(__check_hash_requirements<_Key, _Hash>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__hash_table:883:1: note: in
instantiation of template class
'std::__1::__enforce_unordered_container_requirements<SWrapper, SWrapperHasher,
std::__1::equal_to<SWrapper> >' requested here
typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type
^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/unordered_map:1682:26: note: while
substituting explicitly-specified template arguments into function template
'__diagnose_unordered_container_requirements'
static_assert(sizeof(__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(...
^
hash_map_test.cpp:29:15: note: in instantiation of template class
'std::__1::unordered_multimap<SWrapper, int, SWrapperHasher, std::__1::equal_to<SWrapper>,
std::__1::allocator<std::__1::pair<const SWrapper, int> > >' requested here
auto mm = std::unordered_multimap<SWrapper, int, SWrapperHasher>();
^
1 error generated.
I've tried interpreting the error message, but I'm really at a loss of what to make of it. If anyone has any suggestions as to what's going on here, and how I can work around this on MacOS, it'd be greatly appreciated!
The compiler's complaint unfortunately does not say which requirement was not met. In this case, the problem comes from SWrapperHasher::operator() being private. Marking that public (changing class to struct does this implicitly) makes the unordered map legal.
I would like to use g++ and -Werror, so I have now to disable warnings for 3rd-party libraries I have no control of. The solution provided by http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html works very well, allowing simply to wrap the includes of 3rd party headers with pragmas. Unfortunately, that did no longer work for me in a certain setup where templates are involved. I created the following minimal example of where this approach did not work as expected:
Source file main.cpp
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "hdr.hpp"
#pragma GCC diagnostic error "-Wunused-parameter"
int main() {
return mytemplatefunc(2) + mystandardfunc(3); // will print ONLY ONE warning
}
and the header hdr.hpp
template<typename T>
int mytemplatefunc(T t) {
return 42;
}
int mystandardfunc(int i) {
return 53;
}
compiled using Makefile
CPPFLAGS+=-Wunused-parameter -Werror
main: main.cpp
will produce the following compiler error
g++ -Wunused-parameter -Werror main.cpp -o main
In file included from main.cpp:3:
hdr.hpp: In instantiation of ‘int mytemplatefunc(T) [with T = int]’:
main.cpp:29: instantiated from here
hdr.hpp:2: error: unused parameter ‘t’
make: *** [main] Error 1
shell returned 2
Note that explicit instantiation in main.cpp directly after including the header did not work, and wrapping the call to the template function in main.cpp did not work either. What was puzzling that putting #pragma GCC diagnostic ignored "-Wunused-parameter" in front of the main function silenced the compiler, whilst then adding #pragma GCC diagnostic error "-Wunused-parameter" at the very end of the file caused the compiler to produce the error again. How to solve this puzzle?
(Note, there are dozens of threads about this pragma, but I could not find anyone
that involved such a setup)
The issue is that the instantiation of the template is compiled when you use it, not when it is parsed by the compiler in the header file so it will not issue the warning until it replaces T by int and parses it as a regular function outside the context of the pragma silencing.
The usual way to indicate that you don't intend to use a parameter is to not give it a name:
template<typename T>
int mytemplatefunc(T /* t */)
{ return 42; }
int mystandardfunc(int /* i */)
{ return 53; }
#include <string>
#include <tr1/regex>
#include "TextProcessing.h"
const std::string URL_PATTERN("((http://)[-a-zA-Z0-9#:%_\\+.~#?&//=]+)");
const std::string REPLACEMENT("$&");
std::string textprocessing::processLinks(const std::string & text)
{
// essentially the same regex as in the previous example, but using a dynamic regex
std::tr1::regex url(URL_PATTERN);
// As in Perl, $& is a reference to the sub-string that matched the regex
return std::tr1::regex_replace(text, url, REPLACEMENT);
}
I'm using mingw gcc copiler 4.5.0 version.
I've got the follow error:
%DEV%> mingw32-make all
g++ -Wl,--enable-auto-import -Wall -Wextra -std=c++0x -pedantic -Werror -c -I./include TextProcessing.cpp
cc1plus.exe: warnings being treated as errors
c:\dev\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/tr1_impl/regex:2390:5: error: inline function '_Out_iter std::tr1::regex_replace(_Out_iter, _Bi_iter, _Bi_iter, const std::tr1::basic_regex<_Ch_type, _Rx_traits>&, const std::basic_string<_Ch_type>&, std::tr1::regex_constants::match_flag_type) [with _Out_iter = std::back_insert_iterator<std::basic_string<char> >, _Bi_iter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >, _Rx_traits = std::tr1::regex_traits<char>, _Ch_type = char, std::tr1::regex_constants::match_flag_type = std::bitset<11u>]' used but never defined
mingw32-make: *** [TextProcessing.o] Error 1
Process mingw32-make exited with code 2
Yup, in my g++ include files I also see that regex_replace is declared and not defined. For me, it's in the file /usr/include/c++/4.4.4/tr1_impl/regex . Just above the declaration is a Doxygen comment section which includes:
/** #todo Implement this function. */
Your standard C++ library does not have complete c++0x (now c++1x?) support. Try using Boost's code. See also this answer.