This small test program:
#include <functional>
//template<class T> // <-- with this, gcc compiles ok
template<class T=void>
struct c{
std::function<int(int)> f = [](int i){return i+i;};
};
int main() {};
Clang-3.2 compiles it ok, but from GCC 4.7.1 and 4.8 I am getting strange error:
t.cc:6:31: error: default argument for template parameter for class enclosing ‘struct __lambda0’
function<int(int)> f = [](int i){return i+i;};
^
Is this one of those obscure C++ rules exceptions that nobody knows about or is it a GCC bug?
EDIT
Looks like a bug. I've filed bug report
I think this is a g++ bug with default member initialization. I'm not positive about this, and so have the following supporting evidence:
template<class T=void>
struct c {
std::function<int(int)> f;
c() : f([](int i){return i+i;}) {
}
};
int main() {}
If that works, what you're doing should work too. And it does, even if you construct a c.
Personally, I think default member initialization should be used sparingly and with care. I think it's really easy to create a lot of confusion with it because most people expect all the initialization to be done in the constructor, and member initializers are not necessarily anywhere near any constructor. So they can leave someone scratching their head wondering how some member gets a particular value.
I can see cases, especially with simple, mostly-data classes for which it would work pretty well. But mostly, I think if you have a constructor body of any kind, you should probably not be using default member initialization.
This code will get error anyway on gcc. Yes, without default argument it can be compiled. It can be compiled because struct c isn't used anywhere. But if you try to create instance of this struct, you will get error.
#include <functional>
template<class T>
struct c {
std::function<int(int)> f = [](int i){return i+i;};
};
int main() {
c<int> _c; // error
}
It looks like a bug of gcc. This way can help to avoid problem.
#include <functional>
#include <iostream>
template<class T=void>
struct c {
c() : f([](int i){return i+i;}) {
}
std::function<int(int)> f;
};
int main() {
c<> _c;
std::cout << _c.f(10) << std::endl;
}
Related
Please take a look to this code snippet. I know it does not make much sense, it is just intended to illustrate the problem I am encountering:
#include <iostream>
using namespace std;
struct tBar
{
template <typename T>
void PrintDataAndAddress(const T& thing)
{
cout << thing.mData;
PrintAddress<T>(thing);
}
private:
// friend struct tFoo; // fixes the compilation error
template <typename T>
void PrintAddress(const T& thing)
{
cout << " - " << &thing << endl;
}
};
struct tFoo
{
friend void tBar::PrintDataAndAddress<tFoo>(const tFoo&);
private:
int mData = 42;
};
struct tWidget
{
int mData = 666;
};
int main()
{
tBar bar;
bar.PrintDataAndAddress(tWidget()); // Fine
bar.PrintDataAndAddress(tFoo()); // Compilation error
return 0;
}
The code above triggers the following error:
source_file.cpp:10:3: error: 'PrintAddress' is a private member of 'tBar'
PrintAddress(thing);
source_file.cpp:42:6: note: in instantiation of function template >specialization 'tBar::PrintDataAndAddress' requested here
bar.PrintDataAndAddress(tFoo()); // Compilation error
source_file.cpp:17:7: note: declared private here
void PrintAddress(const T& thing)
but only in Clang++. GCC and MSVC are fine with it (you can quickly test that by pasting that code in http://rextester.com/l/cpp_online_compiler_clang)
It seems as if tBar::PrintDataAndAddress<tFoo>(const tFoo&) is using the same access as tFoo, where it is befriended. I know this because befriending tFoo in tBar fixes this issue. The problem also goes away if tBar::PrintDataAndAddress is a non-template function.
I have not been able to find anything in the Standard that explains this behavior. I believe it could be a bad interpretation of 14.6.5 - temp.inject, but I can't claim I have read all of it.
Does anyone know if Clang is right failing to compile the above code? Can you please quote the relevant C++ standard text if that is the case?
It seems that for this problem to happen, the private member being accessed needs to be a template function. e.g., in the example above, if
we make PrintAddress a non-template function, the code will compile without errors.
Forcing the compiler to instantiate tBar::PrintDataAndAddress<tFoo> before using it solves the problem.
int main()
{
tBar bar;
bar.PrintDataAndAddress(tWidget()); // Fine
auto x = &tBar::PrintDataAndAddress<tFoo>; // <= make it work....
bar.PrintDataAndAddress(tFoo()); // Now fine
return 0;
}
It seems to be a compiler promlem as it looks quite similar to this:
In C++, why isn't it possible to friend a template class member function using the template type of another class?
To be a little bit more precise... In the line bar.PrintDataAndAddress(tFoo()); the compiler has to instanciate the memberfunction tBar::PrintDataAndAddress<tFoo> and at the same time it has to resolve the friend declaration. That are internaly two seperate steps. Apparent the compiler doesn't do it in the rigth order when written in one expression. To force the compiler to instantiate bar.PrintDataAndAddress(tFoo()) first by access to the function pointer these two steps are in the right order.
Try adding this before the friend function
template <typename tFoo>
I have a map like so map<string, unique_ptr<Base>> variables and I am trying to insert data into the map variables.insert(make_pair("foo", new Int(10))) but I am getting to following errors:
error: no matching function for call to ‘std::map<std::__cxx11::basic_string<char>, std::unique_ptr<Base>>::insert(std::pair<const char*, Int*>)’
variables.insert(make_pair("test", new Int(10)));
error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template<typename _Pair, typename = typename
This is my code:
class Base {
public:
Base() {};
virtual ~Base() {};
};
class Int : public Base {
public:
Int(int i) {
this->i = i;
}
Int operator=(int i) {
this->i = i;
}
int i;
};
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", new Int(10)));
}
I think I need a fresh pair of eyes to look at this I'm not sure what this issue is, thanks!
Edit
I'm trying to make a heterogeneous map and there's a class for each data type. But I still get the same error no matter how many there are.
Note: This answer only applies to older versions of the main three compilers:
GCC: Applies to 5.3.1 or earlier. May apply to any version earlier than 6.1.0, but I haven't tested this.
Clang: Applies to 3.7.1 or earlier. May apply to any version earlier than 3.8.0, but I haven't tested this.
Visual Studio: Applies to 19.00.23506.0 or earlier. May apply to any version earlier than 19.00.23720.0, but I haven't tested this.
Conversely, if you have GCC 6.1.0 or later, Clang 3.8.0 or later, or Visual Studio 19.00.23720.0 or later, the original code should compile as is, without either of the modifications suggested in this answer.
[Thanks goes to AndyG for pointing out that it works with later versions of GCC & Clang.]
The problem appears to be that it isn't creating your unique_ptr from your raw pointer.
If you can use C++14, try std::make_unique().
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", make_unique<Int>(10)));
}
If you can't, then try something like this:
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", unique_ptr<Int>(new Int(10))));
}
Interestingly, I noticed a slight difference in how different compilers handle this. Using the following slightly modified version of your code as a test program:
#include <map>
#include <memory>
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
};
class Int : public Base {
public:
Int(int i) {
this->i = i;
}
Int& operator=(int i) {
this->i = i;
// You forgot to return something.
return *this;
}
int i;
};
void set() {
using namespace std;
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", new Int(10)));
// C++14:
// variables.insert(make_pair("test", make_unique<Int>(10)));
// C++11:
// variables.insert(make_pair("test", unique_ptr<Int>(new Int(10))));
// Cheap hack for testing.
cout << static_cast<Int*>(variables["test"].get())->i << endl;
}
int main() {
set();
}
Most compilers* will fail to compile this, unless the initial line is commented out and either of the fixes is uncommented. However, the online MSVC compiler seemed to be able to compile it fine, without needing to uncomment either of the lines. Curiously, the version of MSVC available on Rextester failed to compile it without uncommenting one of the two lines.
* Tested online, with TutorialsPoint GCC, MSVC 2015 online, and Rextester Clang, GCC, and MSVC.
Here is the code:
struct foo {
template<typename T = void>
friend foo f() { return {}; }
};
int main() {
auto x = f(); // clang++ can't find it, g++ can.
}
clang++ 3.4 gives:
fni2.cpp:8:12: error: use of undeclared identifier 'f'
auto x = f(); // clang++ can't find it, g++ can.
^
1 error generated.
g++ 4.9.0 compiles it, but I don't think it should have. This is a related question, but there was no definitive answer. Section 15.4.2/2,4 discuss this, but neither of them say anything to suggest that friend function templates defined in-class should have different visibility from non-template friend functions defined in-class.
This is of academic interest to me only, though it did arise from a question by someone else who may have had an actual use case.
It looks like a g++ bug to me.
Yes, this is an error. I'm surprised it's finding the function. Apparently GCC fails entirely to hide function templates.
This C++03 example also compiles, so it could be a regression:
struct foo {
template<typename T >
friend void f( T ) { }
};
int main() {
f( 3 ); // clang++ can't find it, g++ can.
}
Consider this minimal example:
#include <array>
struct X {
std::array<int,2> a;
X(int i, int j) : a(std::array<int,2>{{i,j}}) {}
// ^^^^^^^^^^^^^^^^^^ ^
};
According to other posts I shouldn't have to explicitly construct a temporary in this situation. I should be able to write:
X(int i, int j) : a{{i,j}} {}
but this and several other (similar) versions I tried are all refused by my (admittedly quite old) g++ 4.5.2. I currently have only that one for experimentation. It says:
error: could not convert ‘{{i, j}}’ to ‘std::array<int, 2ul>’
Is this a limitation of this compiler implementation or what's going on?
The problem is, as a lot of times, the compiler version. The following code works fine with GCC 4.7.1:
#include <array>
struct X{
std::array<int, 2> a;
X() : a{{1,2}} {}
};
int main(){
X x;
}
Live example.
I have the following code which compiles and runs fine under Visual Studio 2008 SP1.
#include <functional>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
class NoncopyableObject : public boost::noncopyable
{
public:
NoncopyableObject(int x) : x_(x) {}
int getValue() const {return x_;}
private:
int x_;
};
template<class F>
class MenuItemDispatcher
{
public:
MenuItemDispatcher(F f) : f_(f) { }
void operator ()(NoncopyableObject& w) const
{
// Invoke the functor
f_(w);
}
private:
typedef boost::function1<void,NoncopyableObject&> FUNC;
FUNC f_;
};
void MenuItem()
{
std::cout << "in MenuItem()\n";
}
template<class F>
MenuItemDispatcher<F> MakeMenuItemDispatcher(F f)
{
return MenuItemDispatcher<F>(f);
}
int main()
{
NoncopyableObject obj(7);
MakeMenuItemDispatcher(boost::bind(&MenuItem))(obj);
}
If I change the boost::bind to std::tr1::bind in main(), I get an error:
error C2248: 'boost::noncopyable_::noncopyable::noncopyable' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'.
This diagnostic occurred in the compiler generated function 'NoncopyableObject::NoncopyableObject(const NoncopyableObject &)'
So it's trying to generate a copy constructor for NoncopyableObject. Anyone know why this might be so please? MenuItemDispatcher's call operator takes a reference to a NoncopyableObject, so I am struggling to see what's going wrong.
This appears to be a difference in how bind is implemented in MS Visual Studio (including 2010) and GNU gcc (I tested 4.4.1 and 4.5.2, both of which work the way you expected)
Consider the following code, given your definitions
auto b = boost::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj); // OK in VS and GCC
replacing boost::bind with std::bind (I'm using 2010, the error message appears to be the same as in your 2008)
auto b = std::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj); // compile error in VS 2010 SP1, OK in GCC
b(std::reference_wrapper<NoncopyableObject>(obj)); // OK in both
So, what happens is that MS's bind() makes a copy of its argument even if the argument is not going to be used, while boost's and GCC's bind() does not bother with that argument at all.
I was able to get your example to compile and run (on 2010) by changing the FUNC typedef to
typedef boost::function1<void, std::tr1::reference_wrapper<NoncopyableObject> > FUNC;