Why can the simplest C++ code not be compiled? - c++

template<class CharType>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
int main()
{
char* narrow_str = 0;
MyString<char>(narrow_str); // error C2040
}
My compiler is VC++ 2013 RC.
The simplest code cannot be compiled because of the error C2040.
error C2040: 'narrow_str' : 'MyString' differs in levels of
indirection from 'char *'
Why?

The problem is this is actually not being parsed as a constructor call but as a variable definition. The problem is you already defined a variable narrow_str. You may have already known this but you can easily fix this by giving it a name.
template<class CharType>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
int main()
{
char* narrow_str = 0;
MyString<char> ns(narrow_str); // error C2040
}
BTW this is also the source of the most vexing parse which occurs when this type of syntax is used in a function argument.
To be honest though I'm surprised that you got a different error because both g++ and clang gave me a clear error.

your syntax in creating a struct is wrong .
change
MyString<char>(narrow_str); // error C2040
to
MyString<char> myString(narrow_str);
will be ok.

Related

Error making tuple containing a unique_ptr

I am trying to create a function func that returns an std::tuple of an std::unique_ptr<A> and a double. However, when I try to create the tuple I receive errors. The code follows:
#include <tuple>
#include <memory>
class A {
public:
A() : data (3){}
private:
double data;
};
std::tuple<std::unique_ptr<A>, double> func(double num) {
std::unique_ptr<A> a = std::make_unique<A>();
std::tuple<std::unique_ptr<A>, double> temp = std::make_tuple(a, num); // ERROR MESSAGE C
return temp;
}
int main() {
return 0;
}
This code produces the following 4 errors in Visual Studio.
Error message A:
tuple(827,18): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to '_Ttype'
Error message B:
tuple(825,83): message : No constructor could take the source type, or constructor overload resolution was ambiguous
Error message C:
Source.cpp(14): message : see reference to function template instantiation 'std::tuple<std::unique_ptr<A,std::default_delete<A>>,double> std::make_tuple<std::unique_ptr<A,std::default_delete<A>>&,double&>(std::unique_ptr<A,std::default_delete<A>> &,double &)' being compiled
Error message D:
tuple(827,12): error C2064: term does not evaluate to a function taking 2 arguments
First, what is the cause of this error? Second, is the A associated with a being placed on the heap?
A std::unique_ptr is not copyable. You are attempting to copy a std::unique_ptr to the tuple, and that will not work. The compiler error message is kind of cryptic, IMO, but that is basically what seems to be the problem.
However, a std::unique_ptr is moveable, thus you can use std::move:
std::tuple<std::unique_ptr<A>, double> temp = std::make_tuple(std::move(a), num);

cast operator function compiles fine in g++ but not in other compilers. Why? [duplicate]

This question already has an answer here:
Operator cast, GCC and clang: which compiler is right?
(1 answer)
Closed 6 years ago.
Consider following program:
struct S {
using T = float;
operator T() { return 9.9f; }
};
int main() {
S m;
S::T t = m;
t = m.operator T(); // Is this correct ?
}
The program compiles fine in g++ ( See live demo here )
But it fails in compilation in clang++, MSVC++ & Intel C++ compiler
clang++ gives following errors ( See live demo here )
main.cpp:8:20: error: unknown type name 'T'; did you mean 'S::T'?
t = m.operator T(); // Is this correct ?
^
S::T
main.cpp:2:11: note: 'S::T' declared here
using T = float;
MSVC++ gives following errors ( See live demo here )
source_file.cpp(8): error C2833: 'operator T' is not a recognized operator or type
source_file.cpp(8): error C2059: syntax error: 'newline'
Intel C++ Compiler also rejects this code ( See live demo here )
So, the question is which compiler is right here ? Is g++ incorrect here or other 3 compilers are incorrect here ? What C++ standard says about this ?
[basic.lookup.classref]/7:
If the id-expression is a conversion-function-id, its conversion-type-id is first looked up in the class of the object expression and the name, if found, is used. Otherwise it is looked up in the context of the entire
postfix-expression. In each of these lookups, only names that denote types or templates whose specializations are types are considered. [ Example:
struct A { };
namespace N {
struct A {
void g() { }
template <class T> operator T();
};
}
int main() {
N::A a;
a.operator A(); // calls N::A::operator N::A
}
— end example]
This indicates that the example could be fine, although in the above example, A has previously been declared as a type name, visible to main.
This was discussed in core issue 156, filed all the way back in 1999:
How about:
struct A { typedef int T; operator T(); };
struct B : A { operator T(); } b;
void foo() {
b.A::operator T(); // 2) error T is not found in the context
// of the postfix-expression?
}
Is this interpretation correct? Or was the intent for this to be an
error only if T was found in both scopes and referred to different
entities?
Erwin Unruh: The intent was that you look in both contexts. If you find it only once, that's the symbol. If you find it in both, both symbols must be "the same" in some respect. (If you don't find it, its an error).
So I'd say that Clang is wrong: the intent, as expressed in the wording to some extent, is that we find T, even if only in the class.

Struct can be declared within method body, but only if it doesn't contain member field initializers. Compiler bug or not?

It took me a good hour to locate this issue. The following code
class Test {
public:
void method();
int _member;
};
void Test::method()
{
struct S {
int s = 0; // same with int s {0};
};
_member;
}
int main(int argc, const char* argv [])
{
return 0;
}
Produces a compilation error:
1>error C2327: 'Test::_member' : is not a type name, static, or
enumerator
1>error C2065: '_member' : undeclared identifier
And the error goes away as soon as I replace int s = 0; with int s;.
This only occurs in MSVC 2013, not 2015. I'm pretty sure it's a compiler bug but I want to make sure it's not some C++ peculiarity that I'm not familiar with (something that changed between C++11 and C++14).
[C++11: 12.6.2] defines NSDMIs in C++11, and neither this section nor any other section in the document defines such a constraint on the syntax. Therefore, it must be an implementation bug.
And, since GCC, Clang and Visual Studio 2015 all accept the code, I don't think any more detailed investigation is worthwhile.

Getting the length of an array. Compiler errors.

I've tried:
template <typename T,unsigned S>
unsigned getArraySize(const T (&v)[S]) { return S; }
after Motti's answer https://stackoverflow.com/a/18078435/512225
but I've got this message:
error C2265: '' : reference to a zero-sized array is illegal
What's wrong with my compiler?
I gave a look at this page:
http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/4b78bcef-4c33-42f1-a4c5-fb6f702ced0b/vs6-c-compile-error-using-getaddrinfo
so I tried this solution:
template <typename T,unsigned S>
unsigned getArraySize(const T v[S]) { return S; }
this compiles, but when I try to use it:
double myX[2] = {7,3};
std::cout << getArraySize(myX) << std::endl;
I get a compilation error:
error C2783: 'unsigned int __cdecl getArraySize(const T [])' : could not deduce template argument for 'S'
Beside changing the compiler, is there a workaround I can use to get the array's size?
This could be a limitation of VC6, have you tried other compilers?
but I've got this message:
error C2265: '' : reference to a zero-sized array is illegal
Arrays with zero size are illegal in C++.
So this probably means you tried with an array of zero size.
this compiles, but when I try to use it:
If you don't use it. Then the compiler is going to ignore a template (even if it has errors). This is because you can not always deduce if a template function is correct without knowing the types involved. So unless there is a call to a template function no error message will be generated.
template <typename T,unsigned S>
unsigned getArraySize(const T v[S]) { return S; }
This fails because you are not allowed to pass arrays as parameters (you can only pass references to arrays).

C++ Garbage collection, templates and operator overriding - can't understand why it throws an error

I am trying to compile a file which defines a garbage collection template and several supporting classes with use of operator overloading. I've tried to run this through MSVC++ 2008, and the compile stops at this particular class:
// (The collector defines gc_object_generic_base which
// inherits from gc_object_generic_base and optionally adds
// collector-specific properties.)
template<class garbage_collector>
class gc_object_base : public garbage_collector::gc_object_collector_base {
public:
gc_object_base() {
garbage_collector::constructing_gc_object_base(this);
}
static void* operator new(size_t sz,
block_construction_locker_base* lock = block_construction_locker<garbage_collector>().get_this())
{
return garbage_collector::allocate(sz, lock);
}
static void operator delete(void* p, block_construction_locker_base* lock) {
return garbage_collector::deallocate(p);
}
static void operator delete(void* p) {
return garbage_collector::deallocate(p);
}
private:
// TODO: are arrays worth implementing?
static void* operator new[](size_t sz) {
assert(0);
return 0;
}
};
Truncated output for brevity's sake:
2>------ Build started: Project: Test, Configuration: Debug Win32 ------
2>Compiling...
2>FlashTest.cc
2>C:\test\gameswf\base\tu_gc.h(133) : error C2059: syntax error : 'string'
2> C:\test\gameswf\base\tu_gc.h(151) : see reference to class template instantiation 'tu_gc::gc_object_base' being compiled
2>C:\test\gameswf\base\tu_gc.h(135) : error C2091: function returns function
2>C:\test\gameswf\base\tu_gc.h(135) : error C2802: static member 'operator new' has no formal parameters
2>C:\test\gameswf\base\tu_gc.h(135) : error C2333: 'tu_gc::gc_object_base::operator new' : error in function declaration; skipping function body
Any ideas on where I should start looking at?
I just had the same pattern of errors in a different project. It seems to happen when someone has done this somewhere:
#define new new(someArgs, someMoreArgs, etc)
It's targeted at simple 'new' expressions, but it breaks down if anyone tries to declare any more 'operator new' thingies.
In the opening lines
template<class garbage_collector>
class gc_object_base : public garbage_collector::gc_object_collector_base {
garbage_collector appears twice here, once as the template parameter and another as an outer-class to gc_object_collector_base, but as it is a template parameter does it not require "typename" here thus:
template<class garbage_collector>
class gc_object_base : public typename garbage_collector::gc_object_collector_base {
There is no mention of string in your code, that I can see. But I would start by ensuring that you first #include <string> before your class delcaration, and then make sure you use std::string as your declarator, rather than just string.