CUDA 8.0: Compile Error with Template Friend in Namespace - c++11

I noticed that the following code compiles with g++/clang++-3.8 but not with nvcc:
#include <tuple> // not used, just to make sure that we have c++11
#include <stdio.h>
namespace a {
template<class T>
class X {
friend T;
};
}
I get the following compile error:
/usr/local/cuda-8.0/bin/nvcc -std=c++11 minimum_cuda_test.cu
nvcc warning : The 'compute_20', 'sm_20', and 'sm_21' architectures are deprecated, and may be removed in a future release (Use -Wno-deprecated-gpu-targets to suppress warning).
minimum_cuda_test.cu:7:10: error: ‘T’ in namespace ‘::’ does not name a type
friend T;
Interestingly, this works with nvcc:
#include <tuple> // not used, just to make sure that we have c++11
#include <stdio.h>
template<class T>
class X {
friend T;
};
Is this a bug in the compiler? I thought nvcc would internally use g++ or clang as a compiler so I am confused why this would work with my local compiler but not with nvcc.

In both cases, the code is being compiled by g++. However, when you pass a .cu file to nvcc, it puts the code through the CUDA C++ front end before passing it to the host compiler. Looking at CUDA 8 with gcc 4.8, I see that the code has been transformed from
namespace a {
template<class T>
class X {
friend T;
};
}
to
namespace a {
template< class T>
class X {
friend ::T;
};
You can see that the front end has replaced the templated friend with an equivalent, but with a prepended anonymous namespace, which is breaking the compilation. I'm not a C++ language lawyer, but this would appear to me to be a bug in the CUDA front end. I would suggest reporting it to NVIDIA.

Related

Can't compile using boost::bimap [duplicate]

With gcc 10.1 and boost 1.73.0, the following code
#include <boost/bimap.hpp>
int main() {
boost::bimap<int, int> lookup;
}
fails to compile with flags -O2 --std=c++20, but will succeed with flags -O2 -std=c++17 (verified with compiler explorer).
This is possibly related to the following issue: https://github.com/boostorg/bimap/pull/15 (deprecated std::allocator<void>)
Is there some workaround I can use for now to get this code to successfully compile with --std=c++20?
The reason behind the error is not that the std::allocator<void> specialization is removed. Actually, it's still valid as the primary template with the void argument. The code fails to compile, because ::rebind is no longer part of std::allocator itself. Instead, an implementation should use std::allocator_traits<Alloc>::rebind_alloc<U>.
Fortunately, most containers usually allow to specify a custom allocator as a template argument. It's also the case for boost::bimap, where an allocator can be the third, fourth or fifth template parameter, according to docs. It defaults to std::allocator, but instead, boost::container::allocator can be used, which does not produce the error:
#include <boost/bimap.hpp>
#include <boost/container/allocator.hpp>
int main() {
boost::bimap<int, int, boost::container::allocator<int>> lookup;
}
This issue has recently been fixed in 6fba6e5. boost::bimap now properly detects if a nested ::rebind is available:
template<class A, class T, class = void>
struct allocator_rebind {
typedef typename detail::alloc_to<A, T>::type type;
};
template<class A, class T>
struct allocator_rebind<A, T,
typename detail::alloc_void<typename A::template rebind<T>::other>::type> {
typedef typename A::template rebind<T>::other type;
};

Static specialized template members in C++17 - why there is difference between GCC and MSVC?

My question is about template static members not about template static functions.
Prior to C++17, when building with GCC and having includes in several CPP files, to avoid "multiple definitions" linker errors of static specialized template members similarly to static functions, they have to be either defined as inline or defined in CPP files (see this).
I have reasons not to define static template members in CPP files so I have to use inline. But to do this I have to switch in both GCC and VS2017 to C++17 because static template inline functions are allowed after C++11 but static template inline members are allowed only after C++17.
But this whole problem does not exist at all in MSVC. This is demonstrated below:
ClassT.h:
template <typename T>
class ClassT
{
public:
static const T CC;
};
template<> const char ClassT<char>::CC = '\\';
Main.cpp:
#include "ClassT.h"
int main()
{
return 0;
}
Test.cpp:
#include "ClassT.h"
This will compile and links without warnings in MSVC but will not compile with GCC giving linker error:
"multiple definition of `ClassT::CC'.
MSVC linker figures out that there is more than one definition and takes only one of them while GCC obviously fails to do this. To solve it for GCC one have to add inline:
template <typename T>
class ClassT
{
public:
inline static const T CC;
};
template<> inline const char ClassT<char>::CC = '\\';
Which however forces to switch to C++17 otherwise will not compile with MSVC.
I wonder which one is correct and according to specification in this case GCC or MSVC linker and how exactly the latter resolves such static members without the inline definition?

vector of maps of non-copyable objects fails to compile in MSVC

The following code (also in https://godbolt.org/z/NSG6Qz) compiles fine in gcc, clang and Visual Studio 2013, but does not compile in recent MSVC versions:
#include <map>
#include <vector>
class MoveOnly {
public:
MoveOnly() {}
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&);
MoveOnly& operator=(MoveOnly&&);
};
int main() {
std::vector<std::map<int, MoveOnly>> vecOfMaps;
std::map<int, MoveOnly> map;
vecOfMaps.push_back(std::move(map));
}
The compilation in all MSVC versions in godbolt fails, in v19.22 with these errors (excerpt):
error C2280: 'std::pair<const _Kty,_Ty>::pair(const std::pair<const _Kty,_Ty> &)':
attempting to reference a deleted function
[...]
note: while compiling class template member function
'std::map<int,MoveOnly,std::less<int>,std::allocator<std::pair<const _Kty,_Ty>>>::map(
const std::map<_Kty,_Ty,std::less<int>,std::allocator<std::pair<const _Kty,_Ty>>> &)'
MSVC does not have problems pushing non-copyable objects into a std::map. Pushing non-copyable objects into std::vector works as well. But pushing the map of non-copyable objects into the vector fails.
Why doesn't this compile?
Is there a workaround that can be applied to the MoveOnly class to make this code compile in MSVC, without losing the non-copyable attribute?

Default value for struct member in c++

It seems that we can not give a default value for struct members in c++,but I find that code as below can compile and run, why? Am I missing something?
struct Type {
int i = 0xffff;
};
Program:
#include <iostream>
using namespace std;
struct Type {
int i = 0xffff;
};
int main() {
// your code goes here
Type val;
std::cout << val.i << std::endl;
return 0;
}
It is going to depend on the compiler you use.
For gcc and clang you need to pass the flag -std=c++11 to the compiler.
Support for member initializer and other c++11 features:
gcc since 4.7. See here.
clang since 3.0. See here.
Visual studio compiler in its 2013 version. See here.
This is correct and introduced in C++11 standard. This concept is known as in-class member initializer
You can check Stroustrup FAQ link on this concept:
http://www.stroustrup.com/C++11FAQ.html#member-init

C2487 with boost members

I try to reorganize our project from static libs into shared libraries of the subprojects.
Well, using VS Compiler all exporting classes needs a _declspec(dllexport) and importing them needs _declspec(dllimport). Works fine. But I got troubles with all classes derived from boost members (e.g. singleton, or ptr_map).
I get the error
error C2487: 'boost::serialization::singleton::instance' :
member of dll interface class may not be declared with dll interface
Microsofts solution is not very helpful, because changing boosts code would maybe not be a good idea;)
Is it not a good idea to export boost derived classes? Does anybody know where this comes from or maybe knows howto fix?
(samplecode below)
thanks!
Here's a sample (mylib.h as shared library project named: "myLib"):
#ifndef _MY_LIB_H_
#define _MY_LIB_H_
#include <string>
#include <boost/serialization/singleton.hpp>
using boost::serialization::singleton;
#ifdef MYLIB_EXPORTS
#define PORT_DLL __declspec(dllexport)
#else
#define PORT_DLL __declspec(dllimport)
#endif
class PORT_DLL MyLib
: singleton<MyLib>
{
public:
std::string GiveMeOutput() const;
};
#endif //_MY_LIB_H_
it's implementation (myLib.cpp)
#include "myLib.h"
std::string
MyLib::GiveMeOutput() const
{
return "some output";
}
an easy main.cpp (as executable project)
#include <iostream>
#include "../myLib/myLib.h"
int main()
{
MyLib lib;
std::cout << lib.GiveMeOutput();
return 0;
}
some points:
VS2010
x64
boost 1.52

Resources