Pointer to member variable as static member - c++

These days I was fiddling with a project study for a data model with a kind of reflection suitable to my needs.
While I got my first study running with the recent stable version of g++, I failed in Visual Studio 19. Too bad, because the latter is my primary platform…
Effectively, I try to store a pointer to member variable into another static member variable. Thereby, it's really desirable for me to do this inline (to fit into my bigger concept).
I reduced the failing detail to the following MCVE:
struct Field { };
struct Class {
template <typename CLASS>
struct BuiltInInfoT {
Field CLASS::*const pField; // member pointer
};
};
struct Object: Class {
Field field1;
static inline BuiltInInfoT<Object> field1BuiltInfo = { &Object::field1 };
};
int main()
{
Object obj;
}
Puzzled that this seems to work in g++ but not in MSVC, I had a look on Compiler Explorer what other compilers say about this. So, I found that recent clang and even the recent ICC (I never used before) accept this.
Live Demo on Compiler Explorer
I tried the same with an even simpler previous example where I didn't use any templates:
#include <iostream>
struct Test {
struct Info { int Test::*p; };
int a;
static inline Info infoA = { &Test::a };
int b;
static inline Info infoB = { &Test::b };
Test(int a, int b): a(a), b(b) { }
};
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Test test(123, 456));
DEBUG(std::cout << (test.*(test.infoA.p)) << '\n');
DEBUG(std::cout << (test.*(test.infoB.p)) << '\n');
}
The result is the same: g++, clang, and ICC compile this fine but MSVC complains.
Live Demo on Compiler Explorer
So, now I'm a bit uncertain.
Is it a bug of MSVC that might be worth to be reported? Or am I expecting something I should not rely on?
Disclaimer:
Of course, I googled this topic the last 3 days and found zillions of tutorials about how to use a member pointer – including the answer to SO: What is the meaning of this star (*) symbol in C++? — Pointer to member I've written myself. Maybe, I was missing the essential keyword but I promise I really tried hard.
In case, you're wondering what I'm trying to do…
The actual project study as Live Demo on coliru from which I made my above MCVE.
Update:
After a long discussion, #doug helped me to find out that this seems to be subject of the Visual Studio property settings. With a clean started project, I got all the above mentioned samples running in my local VS 2019. (Before, I used CMake-generated projects as usual.) I will compare the options of two resp. VS projects to find out the significant difference and post an update if I found something…

#doug gave me the hint that he got my code running in VS 2019 without any complaints.
After a long chat, he gave me the hint to test my above samples in a new created VS solution. All I had to do, was to enable C++17 (/std:c++17) and then MSCV compiled all the samples without complaints.
I must admit that I usually use CMake to prepare the VS solutions:
project (OFM)
cmake_minimum_required(VERSION 3.10.0)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
include_directories("${CMAKE_SOURCE_DIR}")
file(GLOB sources *.cc)
file(GLOB headers *.h)
add_executable(testOFM
${sources} ${headers})
So, I had to find the relevant difference in the VS project settings.
Finally, I found it:
the VS created project contains /permissive-
the CMake created project doesn't.
In the projects settings, it is
- C/C++
- Language
- Standards conformance: Yes (/permissive)
The MS online doc.:
/permissive- (Standards conformance)
Specify standards conformance mode to the compiler. Use this option to help you identify and fix conformance issues in your code, to make it both more correct and more portable.
That's exactly what I want: to be standard conform and portable.
Adjusting this option in my CMake generated project, I got it compiled and running as well.
The demos on Compiler Explorer compiled properly (with the sufficient command line arguments):
Live Demo on Compiler Explorer
Live Demo on Compiler Explorer
and even the initial study (where my trouble started from):
Live Demo on Compiler Explorer
What I wonder: When I wrote my CMake script I already used
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
with the exact intention to be standard conform and portable.
So, there seems to be something else I have to setup in CMake.
(The last resort could be a platform-specific setting but I will investigate to find something else if possible.)
Concerning my problem, I found
CMake Issue #17068:MSVC toolset 14.1+: Set /permissive- when CXX_EXTENSIONS==OFF?
After I have fixed my CMake script with a compiler specific option:
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if (MSVC)
add_compile_options(/permissive-)
endif()
and generated my VS solution / projects again the code compiled without any complaints as well.

#Scheff has identified a problem likely to affect others re inline static member initialization. It's particularly problematic as it differently affects compiler explorer c++17 defaults v MSVC IDE c++17 defaults. See his answer and analysis:
Using the default c++ settings (c++14) for MSVC which doesn't allow inline static members.
Change the setting to c++17 or higher. This is the usual cause of inline static initialization on the same line.
However, after chat, it turns out c++17 is being used but the difference is that it's being used with CMake. Apparently there is a difference between CMake and an MSBuild solution/project file. The latter works, the former doesn't. Under investigation and will update with results.

Related

c++20, clang 13.0.0, u8string support

I'm using clang 13.0.0 in a CMAKE-based project, CMAKE_CXX_STANDARD is defined as 20. The following code causes a compilation error (no type named 'u8string' in namespace 'std'):
#include <iostream>
#include <string>
int main() {
#ifdef __cpp_char8_t
std::u8string sss = u8"a"; // <---- this branch is picked up
#else
std::string sss = "b"
#endif
return 0;
}
Below is the CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
project(clang_test)
add_executable(clang_test main.cpp)
Am I missing something or is it a clang bug? I mean, if std::u8string is not yet there, the macro shouldn't be defined, right? By the way, if you know the way to undefine it somehow with the CMake, please, share your experience. Here the topic starter faces the same problem, I think, but there is no solution proposed yet.
Update: the platform is RHEL 8.4
Update 2: moved the 'project' call below the compiler settings in the CMakeLists.txt
Frank's suggestion was correct - the problem is in that Clang was using an older version of libstdc++ and not libc++;
target_compile_options(clang_test PRIVATE -stdlib=libc++)
fixes the issue for me. Though I don't entirely understand why it doesn't work with libstdc++, if you have any idea, please, share it here - I assume that this is a separate question.
Also, Tsyvarev's point is indeed a very important one, and the compiler should be set before the project call. I've corrected the example in my question.
Update: Finally I understand the reason why it fails: __cpp_char8_t is not sufficient for std::u8string, __cpp_lib_char8_t should be used instead.
Thanks everyone for your help!

clang-cl doesn't allow operator-overloads for __m128 because it's not a class or enum? Workaround to make it like MSVC?

The following code builds just fine under cl, but fails under clang-cl:
#define NUDGE_FORCEINLINE __forceinline
NUDGE_FORCEINLINE __m128 operator-(__m128 a) {
return _mm_xor_ps(a, _mm_set1_ps(-0.0f));
}
This is the error message:
..\nudge.cpp(65,26): error: overloaded 'operator-' must have at least one parameter of class or enumeration type
NUDGE_FORCEINLINE __m128 operator-(__m128 a) {
^
The code is from rasmusbarr/nudge, an experiment which seems to be abandoned since 2017.
Setup (CMake/VSCode):
cl with VS Build Tools 2019 v16.8.2
clang-cl with C++ Clang Tools for Windows 10.0.0 (VS Build Tools 2019 v16.8.2)
cmake_minimum_required(VERSION 3.18.0)
project(nudge LANGUAGES C CXX)
add_executable(tests "nudge.cpp" "tests/main.cpp")
target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR})
Research:
I came across these two sources (1, 2) that seem to point out that the reason might be clang-cl does not consider __m128 to be a struct type. They fixed it in (1), but it seems that they just disable SSE for some platforms.
Although it was a long shot, I tried compiling with the VS version of immintrin.h and intrin.h but that path led nowhere.
I also noticed that someone else who build this experiment used the c++11 standard so I tried that too by setting set(CMAKE_CXX_STANDARD 11) in cmake. No change.
Question:
How can I modify the code (or change compiler flags) in order to build rasmusbarr/nudge with clang-cl?
Thank you

Qt Creator displaying stale or wrong errors

I'm using Qt Creator 4.10.2 as IDE on a Fedora Workstation installation, trying to get through excercises in "C++ Crash Course". One of the excercises requires you to declare a concept and apply it to a function. Here's my code:
template<typename T> concept Integer = std::is_integral<T>::value;
template<Integer T> T mode (const T* values, size_t length) {...}
Initially, the build environment wasn't configured for C++20 or using concepts, so I added the following to my CMakeLists.txt:
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconcepts")
Not sure if this is the right way, just something I googled up (possibly on this very site). Now, the project is building and running as it should... but the editor shows an avalanche of errors and warnings ("unknown type name Integer" etc.). "Tools->C++->Inspect C++ Code Model" shows -fconcepts and -std=c++2a, so supposedly it picked up my settings correctly.
This issue does not stop me from continuing with the examples but it's very uncomfortable working with dozens of errors always on. I believe I misconfigured the IDE somewhere, but how exactly? Thank you for your time.

Cannot set __cplusplus to C++17 standard with Visual Studio and CMake

I've a CMake project that's opened with Visual Studio 2019. I need c++17 features for my code, so I've set the corresponding flag in the CMakeLists.txt
cmake_minimum_required (VERSION 3.10.0)
project (datalog)
message (STATUS "Building project ${PROJECT_NAME}")
find_package(stxxl CONFIG REQUIRED)
include_directories (${CMAKE_SOURCE_DIR}/src)
set (PROJECT_SRC
main.cpp
)
add_executable (${PROJECT_NAME} ${PROJECT_SRC})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
target_link_libraries(${PROJECT_NAME} stxxl)
When I build I obtain a lot of errors, because the library that I'm linking, stxxl, installed with vcpkg, has the following piece of code:
STXXL_BEGIN_NAMESPACE
template <class Type>
struct compat_unique_ptr {
#if __cplusplus >= 201103L && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40400)
typedef std::unique_ptr<Type> result;
#else
// auto_ptr is inherently broken and is deprecated by unique_ptr in c++0x
typedef std::auto_ptr<Type> result;
#endif
};
STXXL_END_NAMESPACE
The problem is that __cplusplus has value 199711L instead of the correct value 201703L, so code tries to use auto_ptr that's removed in C++17 standard.
I've also tried to set the flag manually in Visual Studio, adding this section in the CmakeLists.txt
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17 /Zc:__cplusplus")
endif()
But nothing changes. I'm also using some C++17 features, so going back at the moment is not an option.
I can manually update the stxxl header file to get rid of the macro, but it's a workaround, and every developer should create the same fix. Instead, I'd like to know why I'm getting the error and how to set the macro to the correct value with Visual Studio and CMake. Do you have any suggestion?
As far as i can tell from this, you need to add /Zc:__cplusplus manually (at least for now).
Your CMakeList snippet worked for me, are you sure, that __cplusplus is actually set incorrectly and it's not just the __GNUC__ Macro, that's missing?
That said, I'd recommend to test if the version of VisualStudio is actually new enough:
# /Zc:__cplusplus is required to make __cplusplus accurate
# /Zc:__cplusplus is available starting with Visual Studio 2017 version 15.7
# (according to https://learn.microsoft.com/en-us/cpp/build/reference/zc-cplusplus)
# That version is equivalent to _MSC_VER==1914
# (according to https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019)
# CMake's ${MSVC_VERSION} is equivalent to _MSC_VER
# (according to https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html#variable:MSVC_VERSION)
if ((MSVC) AND (MSVC_VERSION GREATER_EQUAL 1914))
target_compile_options(stxxl INTERFACE "/Zc:__cplusplus")
endif()
Note: I used target_compile_options to add the necessary option to the interface of your library target. This way all targets, that depend on that library (via target_link_libraries) will be compiled with that flag, but targets, that don't need it (and might be incompatible with it) won't get it.
If you want to add the flag to one of your own targets, you can use target_compile_options(stxxl PUBLIC "/Zc:__cplusplus") (PUBLIC instead of INTERFACE). INTERFACE means the option is used when other targets depend on that target, PRIVATE means the option is used for the target itself and PUBLIC means both. (IMHO this artical explains it well.)
Apart from that, you shouldn't set the c++ standard version via compile flags, but instead using target_compile_features if the newer version is required and using
set_target_properties(your_target_name PROPERTIES CXX_STANDARD 17) if you just wish to use the newer version if it is available.
In your case the latter is probably sufficient as your codesnippet has a fallback if the c++ version is older.
If changing the code of stxxl (via pull request, etc.) is an option, the code could test _MSVC_LANG and _MSC_VER. This way it would work without requiring /Zc:__cplusplus.
I think what you need is target_compile_definitions, where you can define arbitrary macros in CMake and pass to compiler.

GCC versions/flags and FAM

I'm trying to port our build system from make to CMake, and I encountered a problem that surprisingly not "Googleable"
Our code is C++ 11/14, compiles fine with GCC6.2, the make applies zillion switches when invoking GCC, mostly pedantic warnings. I built a CMake system that compiles (GCC 6.3) most of the code without a problem but some modules failed to build because of the following
flexible array member ‘blahblah’ not at end of ‘struct‘
Aside why it appears in the C++ code. Why did it compile in the make based system? AFAIK, flexible array is not a part of C++ standard. GCC specific extension? What command line switch controls FAM behavior? How do I make it compile as it did in the original make system?
In case someone needs a snippet of compiled code
struct Foo
{
int _10;
double _20;
int a[];
};
struct Bar
{
Foo foo;
double _1;
int _2;
}
To add more context, the cmake file
cmake_minimum_required(VERSION 3.9)
project(foo VERSION ${FOO_VERSION} DESCRIPTION "foo")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_STANDARD 99)
add_executable(foo foo.cpp foo_backup.cpp main.cpp)
set_target_properties(foo PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(foo PUBLIC ${CMAKE_SOURCE_DIR}/lib/include ${CMAKE_SOURCE_DIR}/lib/include/bar)
How do I make it compile as it did in the original make system
Revert to GCC 6.2. This -pedantic error was introduced for C++ in GCC 6.3.
See compilation with 6.2 and compilation with 6.3
Disabling pedantic compilation will remove the error but entail other relaxations.