The code bellow compiles without a warning on GCC and issues an error with clang (any c++11 compatible versions of both clang and GCC).
Which compiler is right with respect to the standard?
Specifically, is it allowed to declare as friend a non partially specialized template alias which is a partial template specialization of a class?
This makes me think that it might not be allowed:
cppreference says: "Friend declarations cannot refer to partial specializations [...]".
And also: "A type alias declaration introduces a name which can be used as a synonym for the type denoted by type-id. It does not introduce a new type [...]".
Finally: "Both function template and class template declarations may appear with the friend specifier [...]". It implicitly excludes the possibility for a template alias to be a friend of a class as an actual template alias but rather as the aliased class template, which is a partial specialization in the snippet bellow.
However, this makes me think that it might be allowed:
cppreference says : "An alias template is a template [...]". I undestand that a template alias is a distinct template. By consequence, declaring it as friend as in the following example without partial specilization of the class template alias is valid... Or not.
This code (not from me) also gives a workaround and let me think that there is no obvious reason for making the following code ill-formed.
This post asks a very similar question but no clear answer was provided with respect to the specific usage of an intermediate template alias.
template<typename T,typename N> class B{};
template<typename T> class A{
// template<typename U> friend class B<T,U>; fails as expected
template<typename N> using alias = B<T,N>;
template<typename N> friend class alias;
};
Intent: legal way to declare a partial specialization as friend using an intermediate alias (workaround).
Result: GCC is happy with it and produces the intended behaviour. Clang produces the following error:
<source>:7:35: error: redefinition of 'alias' as different kind of symbol
template<typename N> friend class alias;
^
<source>:6:22: note: previous definition is here
template<typename N> using alias = B<T,N>;
Related
I'm trying to use the function traits that was posted as the marked answer here:
Is it possible to figure out the parameter type and return type of a lambda?
While trying to compile it with msvc 19.16.27034 I get the following errors:
Error C2825 'T': must be a class or namespace when followed by '::'
Error C2510 'T': left of '::' must be a class/struct/union
Error C2065 '()': undeclared identifier
Error C2955 'function_traits': use of class template requires template argument list
On godbolt this works on any compiler but for some reason on my local machine I can't get this to compile because of these errors. Am I missing something?
UPDATE:
Adding std::remove_reference_t
template <typename T>
struct function_traits
: public function_traits<decltype(&std::remove_reference_t<T>::operator())>
{
};
to the declaration solves the problem.
The weird part is that even without any instantiation to the template I still get this error on the specified compiler, unless I'm adding std::remove_reference_t.
Anyone can explain this weird behaviour?
I am confusion.
I'm learning about the ofstream, it seems that it's really a basic_ofstream according to:
https://en.cppreference.com/w/cpp/io/basic_ofstream/basic_ofstream
https://msdn.microsoft.com/en-us/library/7z434859.aspx
What is the reason for a class named basic_ofstream with a constructor named ofstream? 'basic' implies that there is a non-basic version. Why is the constructor name different than the class name?
There is no constructor named ofstream (constructors don't have names), and there's no class named basic_ofstream (despite of what Microsoft documentation claims).
basic_ofstream is a class template (which is different from a class), and ofstream is a typedef name a.k.a. type alias that refers to one instantiation of that template, specifically to basic_ofstream<char>.
wofstream is another such name that refers to basic_ofstream<wchar_t>.
This is the naming convention that the C++ standard library uses to define different variants of types that differ in the character type they use. Another set of names that follows this convention is basic_string, string and wstring.
This is not constructor named differently. It's a specialization. So basic_ofstream is a template. Then you have two "shortcut names":
ofstream for basic_ofstream<char>
wofstream for basic_ofstream<wchar_t>
Why are they named basic... maybe because standard library provides only basic versions and client can write non-basic classes and plug them in. If you look at c++ standard io library diagram, all components are prefixed as "basic".
It's usually by replacing basic_streambuf any tying custom streambuf to stream. One example taken from boost
#include <ostream>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
namespace io = boost::iostreams;
int main()
{
io::stream_buffer<io::file_sink> buf("log.txt");
std::ostream out(&buf);
// out writes to log.txt
}
It's a buffer implementation working with std::ostream.
If you want to explore fancy implementations you can checkout more from boost::iostreams library and their examples. Nice one is with gzip. It works with ifstream:
#include <fstream>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
int main()
{
using namespace std;
ifstream file("hello.gz", ios_base::in | ios_base::binary);
filtering_streambuf<input> in;
in.push(gzip_decompressor());
in.push(file);
boost::iostreams::copy(in, cout);
}
Following code does not compile with clang-700.1.81 and it's standard library:
#include <memory>
class something;
std::unique_ptr<something> external_function();
std::unique_ptr<something> local_function()
{
auto thing = external_function();
return thing;
}
The diagnostics by clang:
......./include/c++/v1/memory:2626:46: note: in instantiation of member function 'std::__1::unique_ptr.....requested here
_LIBCPP_INLINE_VISIBILITY ~unique_ptr() {reset();}
^
test.cc:10:18: note: in instantiation of member function 'std::__1::unique_ptr<something, std::__1::default_delete<something> >::~unique_ptr' requested here
auto thing = external_function();
^
test.cc:4:7: note: forward declaration of 'something'
class something;
^
I guess it is trying to destroy the unique_ptr after copying it as return value, but is this really necessary? It is going be moved anyways, does it need to check if it can copy before realizing that it is easier to move it?
I could of course do this easily with a naked pointer.
Is there some other way to allow a uniqe_ptr to just "pass through" a translation unit, as shown in the example, without including extra header to get the definition of class something?
------EDIT--------
Also tried with GCC 5.3.0 and gnu libstdc++
Does not compile as well, with similar error messages.
------EDIT----
I think it is just trying to destroy the original thing object.
Thanks to Rudolf for the deleter idea ( a bit messy, but only option for this )
Looking at the library code I found this in unique_ptr's code:
if (__tmp)
__ptr_.second()(__tmp);
where second(_tmp) destructs the object pointed to. Even though it is never called, the compiler needs a definition to compile it. This is silly, but apparently gotta live with it.
From cppreference.com:
std::unique_ptr may be constructed for an incomplete type T, such as to facilitate the use as a handle in the Pimpl idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr. (Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where T is incomplete).
Thus, with a custom deleter you can use a forward declared class if the full declaration is available for the deleter:
#include <memory>
class Foo;
class FooDeleter
{
public:
void operator()(Foo* pInstance);
};
std::unique_ptr<Foo, FooDeleter> pFoo;
class Foo
{
};
void FooDeleter::operator()(Foo* pInstance)
{
delete pInstance;
}
I started going through boost library recently and
came across a sample code which is as follows
Class A : public boost::static_visitor<bool>
typename A::result_type();
I couldn't understand what result_type() will do here.
It result type is a nested typedef indicating the return type of the visitor.
This is so boost::apply_visitor knows what return to expect (even if the various overloads of operator() return possibly different types).
I have C++/CLI class that defines a property:
public ref class AbstractOffer
{
public:
AbstractOffer();
property String^ Body;
};
In some function the AbstractOffer class is passed by const ref
foo(const AbstractOffer^ ao)
{
ao->Body;
}
When I call the property the method compiler gives the following error :-
error C2662: 'ivrworx::interop::AbstractOffer::Body::get' : cannot
convert 'this' pointer from 'const ivrworx::interop::AbstractOffer'
to 'ivrworx::interop::AbstractOffer %' 1> Conversion loses
qualifiers
It seems somehow connected to const. How can I call the Body property of the object if the object reference is passed by const?
The const qualifier is a problem in C++/CLI. It is only meaningful when it can be checked and that's not in general possible in .NET. It is of course not a problem when you only have one kind of compiler and that compiler follows strict language rules. Like C++. But .NET supports many languages, your method could be easily called from a Cobol.NET program for example. The odds of ever getting const-correctness added to the Cobol language are zero.
The compiler does compile code with const qualifiers and does make an effort to check when it can. Which is why you got the diagnostic. That can even work when the declaration exists in another assembly, as long as it was compiled with C++/CLI, the compiler emits modopt annotations in the metadata.
But there are limitations with that. Properties are one of them, you can't add the const qualifier to the getter, or a member function in general, you'll get slapped with C3842.
Best thing to do is to use C++/CLI for what it is good at, it is an interop language. And const qualifiers just don't work well in an interop scenario.
The only way I know to get round this is the cast away the const-ness. As long as you don't modify the object, it should be fine. (If you do modify it, I've no idea what the outcome will be).
i.e. change your function to be
void foo(const AbstractOffer^ ao)
{
const_cast<AbstractOffer^>(ao)->Body;
}