473,394 Members | 1,703 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

C2440: Generic argument and nullptr

I'm having a hard time understanding why I get
the following error with the code shown.

Can someone explain?

public ref class Class1
{
};

generic<typename Twhere T: Class1, gcnew()
public ref class Gen
{
public:
Gen() {}

T GetVal(bool condition)
{
if( condition )
return gcnew T();
else
return nullptr; // <----- Error: C2440
}

};

public ref class test
{
public:
test()
{
Gen<Class1^gen = gcnew Gen<Class1^>();
Class1^ x1 = nullptr;
Class1^ x2 = gcnew Class1();
Class1^ x3 = gen->GetVal(false);
}
};

// C2440: 'return' : cannot convert from 'nullptr' to 'T'


--
Tony M.
Oct 16 '06 #1
11 3770
"Tony Maresca" <to**@whereever.comwrote in message
news:%2****************@TK2MSFTNGP05.phx.gbl...
I'm having a hard time understanding why I get
the following error with the code shown.

Can someone explain?
Read the entire error message:

genericnull1016.cpp(16) : error C2440: 'return' : cannot convert from
'nullptr' to 'T'
'T' may be a value type at runtime: consider using 'T()' instead

Since there's no provision in .NET generics to restrict a type parameter to
be a reference type (or a value type, for that matter), there's no way to
represent nullptr within a generic.

In short, you'll have to change your design - you simply can't count on
being able to return nullptr from a generic method.

-cd
Oct 16 '06 #2
Tony Maresca wrote:
Excuse me, but I showed the entire error message
in my OP:

"C2440: 'return' : cannot convert from 'nullptr' to 'T'"

That was the entire error message, nothing more.
Check the output window instead of the task list. Many C++ compiler error
messages are more than 1 line long - the task list/error lists shows only
the first line of the message.
>
>Since there's no provision in .NET generics to restrict
a type parameter to be a reference type (or a value type,
for that matter), there's no way to represent nullptr
within a generic.

Sorry, but it looks to me that the constraint explicitly
requires a reference type for the generic parameter.
I agree - it looks like it should require a ref class, since a value type
can't derive from a ref class. Apparently the C++ compiler disagrees - Have
you tried the equivalent code in C#? If that compiles, then this would have
to be a compiler bug, but it may well be a .NET limitation.

-cd
Oct 17 '06 #3
Tony Maresca wrote:
But, in C# if the type is a reference type, then null can
be assigned to a variable of the generic type.
Have you tried what the error message recommended? This works for me:

T GetVal(bool condition)
{
if( condition )
return gcnew T();
else
return T(); // nullptr
}

Note that in C++ the T() syntax is essencially a default initialization.
If there's no user-defined default constructor, the compiler will simply
fill the variable with 0 bytes. In your case, T is Class1^, so T() is
Class1^(), which is identical to nullptr.

int main()
{
Gen<Class1^gen;
Class1^ x3 = gen.GetVal(false);
if(x3 == nullptr)
{
Console::WriteLine("success");
}
}

Tom
Oct 17 '06 #4
generic<typename Twhere T: Class1, gcnew()
public ref class Gen
{
public:
Gen() {}
- T GetVal(bool condition)
+ T^ GetVal(bool condition)
{
if( condition )
return gcnew T();
else
return nullptr; // <----- Error: C2440
}

};
A return type of 'T' is marked modopt(IsImplicitlyDereferenced), which makes
no sense for nullptr.
Oct 18 '06 #5

"Tamas Demjen" <td*****@yahoo.comwrote in message
news:%2****************@TK2MSFTNGP04.phx.gbl...
Tony Maresca wrote:
>But, in C# if the type is a reference type, then null can
be assigned to a variable of the generic type.

Have you tried what the error message recommended? This works for me:

T GetVal(bool condition)
{
if( condition )
return gcnew T();
else
return T(); // nullptr
}

Note that in C++ the T() syntax is essencially a default initialization.
If there's no user-defined default constructor, the compiler will simply
fill the variable with 0 bytes. In your case, T is Class1^, so T() is
Class1^(), which is identical to nullptr.
No, T() will return the same as gcnew T(), which is to say a pass-as-copy
tracking reference(!) to a default Class1. The problem is that T is Class1,
not Class1^, and while nullptr is a valid value for Class1^ it isn't a valid
value for Class1. Return a T^ tracking handle instead of a T.
Oct 18 '06 #6
Ben Voigt wrote:
>>Note that in C++ the T() syntax is essencially a default initialization.
If there's no user-defined default constructor, the compiler will simply
fill the variable with 0 bytes. In your case, T is Class1^, so T() is
Class1^(), which is identical to nullptr.


No, T() will return the same as gcnew T(), which is to say a pass-as-copy
tracking reference(!) to a default Class1. The problem is that T is Class1,
not Class1^, and while nullptr is a valid value for Class1^ it isn't a valid
value for Class1. Return a T^ tracking handle instead of a T.
Sorry, but you're wrong here. The generic is instantiated like this:
Gen<Class1^>

so T is Class1^, not Class1. It really works, return T() returns
nullptr, I verified it with the following test code. T() does not create
any Class1 instance, it creates a nullptr of type Class1^.

public ref class Class1
{
public:
Class1() { Console::WriteLine("c'tor"); }
};

generic<typename Twhere T: Class1, gcnew()
public ref class Gen
{
public:
Gen() {}

T GetVal(bool condition)
{
if( condition )
return gcnew T();
else
return T(); // <----- nullptr
}

};

public ref class Test
{
public:
Test()
{
Gen<Class1^gen;
Class1^ x3 = gen.GetVal(false); // <------ try it: true or false
if(x3 == nullptr)
{
Console::WriteLine("yes, it's nullptr");
}
}
};

This code prints "yes, it's nullptr", which means the code works as I
described it. It doesn't create any instances of Class1... ever. It
returns a nullptr.

Now if I change the test code to gen.GetVal(true), the program prints
"c'tor". Of course in that case a Class1 instance is constructed, and
the result is not nullptr.

T is Class1^, and return T() is essencially the same as return nullptr,
with no Class1 instance constructed whatsoever. I really tried this, I'm
not just guessing here. It's something I didn't know before either.

Tom
Oct 19 '06 #7
Ben Voigt wrote:
+ T^ GetVal(bool condition)
Unfortunately this doesn't compile. The error message is:

error C3229: 'T ^' : indirections on a generic type parameter are not
allowed
compiler using 'T' to continue parsing

Tom
Oct 19 '06 #8
Tony Maresca wrote:
Thanks, this is the part that I was missing. I never saw
any reference to the T() syntax as its used here.
The Error List window only shows the first line of error messages. Your
original error message had two lines, as Carl explained it earlier. To
read the full error message, switch to the Output tab.

I didn't know all this stuff either. I just compiled your code, and
noticed that the compiler suggested to use return T(). First I thought
it was ridiculous as hell, but tried it nonetheless, and it turned out
to be the solution. First it may look like return T() creates an
instance of Class1, but in this case it just creates a nullptr. Yes, it
is very odd, terribly confusing too, I have to admit it.

Tom
Oct 19 '06 #9

"Tamas Demjen" <td*****@yahoo.comwrote in message
news:%2******************@TK2MSFTNGP05.phx.gbl...
Ben Voigt wrote:
>>>Note that in C++ the T() syntax is essencially a default initialization.
If there's no user-defined default constructor, the compiler will simply
fill the variable with 0 bytes. In your case, T is Class1^, so T() is
Class1^(), which is identical to nullptr.


No, T() will return the same as gcnew T(), which is to say a pass-as-copy
tracking reference(!) to a default Class1. The problem is that T is
Class1, not Class1^, and while nullptr is a valid value for Class1^ it
isn't a valid value for Class1. Return a T^ tracking handle instead of a
T.

Sorry, but you're wrong here. The generic is instantiated like this:
Gen<Class1^>
Sorry I missed that. Then T() is indeed just the C++ equivalent of C#'s
default keyword and will be nullptr.

But then shouldn't gcnew T() also give nullptr?

In C++, T() and new T() both call the same constructor, which is to say the
default constructor for T. Outside a generic, gcnew works essentially the
same as new, only it constructs an object on the managed heap instead of
unmanaged, but like new it allocates heap memory and returns an address.
>
so T is Class1^, not Class1. It really works, return T() returns nullptr,
I verified it with the following test code. T() does not create any Class1
instance, it creates a nullptr of type Class1^.

public ref class Class1
{
public:
Class1() { Console::WriteLine("c'tor"); }
};

generic<typename Twhere T: Class1, gcnew()
public ref class Gen
{
public:
Gen() {}

T GetVal(bool condition)
{
if( condition )
return gcnew T();
else
return T(); // <----- nullptr
}

};

public ref class Test
{
public:
Test()
{
Gen<Class1^gen;
Class1^ x3 = gen.GetVal(false); // <------ try it: true or false
if(x3 == nullptr)
{
Console::WriteLine("yes, it's nullptr");
}
}
};

This code prints "yes, it's nullptr", which means the code works as I
described it. It doesn't create any instances of Class1... ever. It
returns a nullptr.

Now if I change the test code to gen.GetVal(true), the program prints
"c'tor". Of course in that case a Class1 instance is constructed, and the
result is not nullptr.

T is Class1^, and return T() is essencially the same as return nullptr,
with no Class1 instance constructed whatsoever. I really tried this, I'm
not just guessing here. It's something I didn't know before either.

Tom

Oct 20 '06 #10

"Tamas Demjen" <td*****@yahoo.comwrote in message
news:OA**************@TK2MSFTNGP05.phx.gbl...
Ben Voigt wrote:
>+ T^ GetVal(bool condition)

Unfortunately this doesn't compile. The error message is:

error C3229: 'T ^' : indirections on a generic type parameter are not
allowed
compiler using 'T' to continue parsing

Tom
I never would have guessed that.... but then I use templates in C++ and
generics in C#. Template semantics are well known and understood, why
couldn't Microsoft just build generics on top of what we already know?
Oct 20 '06 #11
Ben Voigt wrote:
But then shouldn't gcnew T() also give nullptr?

In C++, T() and new T() both call the same constructor, which is to say the
default constructor for T.
I agree, I have a feeling that generics are implemented in a very
confusing way in C++/CLI. Just consider the where clause:

where T: Class1

it's a constraint that specifies that T can only be Class1^. The whole
generics implementation looks C#-ish to me, but that's inexact in C++.
In some of the expressions T stands for Class1, and in others it
represents Class1^. It's a big mess, if you ask me. (It's fine for C#,
but is so not C++-like).

A possible reason behind this is that T can be either a value type or a
reference type, and they had to find a way to use a uniform syntax for
both. That's only possible if T is interpreted in a context-sensitive
way (sometimes as Class1, sometimes as Class1^).

I discovered the following context rule. If T is a value type, T()
creates a new object, and gcnew T() generates an error. If T is a
reference type, T() is nullptr and gcnew T() creates a new object.

Tom
Oct 20 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Andreas Huber | last post by:
What follows is a discussion of my experience with .NET generics & the ..NET framework (as implemented in the Visual Studio 2005 Beta 1), which leads to questions as to why certain things are the...
8
by: JAL | last post by:
Here is my first attempt at a deterministic collection using Generics, apologies for C#. I will try to convert to C++/cli. using System; using System.Collections.Generic; using System.Text; ...
3
by: KH | last post by:
I can't seem to figure this one out... I've searched MSDN and Goog, and made my best guesses to no avail,, so help would be much appreciated! public ref class T sealed : public...
2
by: Rune Vistnes | last post by:
Hey, I am trying to wrap an unmanaged library in managed c++ so that I can use this library in other .NET languages, such as C#. I've been successful for the most part this far, but I'm having a...
2
by: Bruce Arnold | last post by:
I have a program that works fine using Remove and Add to update a value. The program processes a log file from a router and counts the hits based on url. It bothers me to use Remove/Add when all...
0
by: craig.conboy | last post by:
Using MC++ .Net 2.0, with the CLR Profiler (from Microsoft) I am seeing that 3 blocks of memory, each ~48MB in size, being allocated by some code that initializes a managed array. It is a jagged...
9
by: mps | last post by:
I want to define a class that has a generic parameter that is itself a generic class. For example, if I have a generic IQueue<Tinterface, and class A wants to make use of a generic class that...
2
by: software | last post by:
Hello, I am a new bee to c++/cli, here's my question: I have a template version of a smart pointer class I can't use in my application because I need to use it in more than one assembly. I...
26
by: raylopez99 | last post by:
Here is a good example that shows generic delegate types. Read this through and you'll have an excellent understanding of how to use these types. You might say that the combination of the generic...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.