Please help, how do I fix error C4346 with the code here...

  • Thread starter Thread starter Jeff Chang
  • Start date Start date
J

Jeff Chang

Hi all,

Below is the sample c++ code that cause error C4346 in vs-2009 pro. I have a
"Record" struct within the Database class, and has a "Retrive(int n)" member
function that return "Record*" type. If I have my implementation code
defined within the class then everything works fine. However if I put it
outside the class I get error C4346. I prefer to put the implementation code
outside the class to keep the code clean. Please help.


Thanks
Jeff





//---------------------------------------------------------------------------
#include <iostream>
#include <string>
using namespace std;
const int Maximum = 100;

//---------------------------------------------------------------------------
// Code-1: Database class definition, has a nested "Record" struct inside
//---------------------------------------------------------------------------
template<typename Object>
class Database {
public:
struct Record {
Object ID;
Record( Object a=Object() ) : ID(a) {}
};

private:
Record items[Maximum];

public:
int Count;
Database() : Count(0) { }

// the following declaration with Code-2 definition will
cause error C4346
Record* Retrieve(const int n);

// however if I replace the code above and those Code-2 with
this the error is gone
// Record* Retrieve(const int n) {
// return &items[n];
// }

void Add(const Record& d) {
if ( Count<Maximum ) items[Count++] = d;
}
};

//---------------------------------------------------------------------------
// Code-2: Retrieve() definition with the return type of "Record".
// Receive the following error when trying to compile
// warning C4346: 'Database<Object>::Record' : dependent name is not a
type
// 1> prefix with 'typename' to indicate a type
// error C2143: syntax error : missing ';' before
'Database<Object>::Retrieve'
// error C4430: missing type specifier - int assumed. Note: C++ does
not support default-int
// fatal error C1903: unable to recover from previous error(s);
stopping compilation
//---------------------------------------------------------------------------
template<typename Object>
Database<Object>::Record*
Database<Object>::Retrieve(const int n) {
return &items[n];
}


//---------------------------------------------------------------------------
// Main Driver
//---------------------------------------------------------------------------
int main(int argc, char* argv[]) {

typedef Database<int>::Record rec;
Database<int> lists;
lists.Add( rec(12) );
lists.Add( rec(13) );
lists.Add( rec(15) );
lists.Add( rec(18) );
lists.Add( rec(17) );

cout << "Record ID\n";
for(int i = 0; i < lists.Count; i++)
cout << lists.Retrieve(i)->ID << endl;

cout << endl;
system("pause");
return 0;
}


//---------------------------------------------------------------------------
// Program Output
//---------------------------------------------------------------------------
Record ID
12
13
15

Press any key to continue . . .
 
Jeff said:
Hi all,

Below is the sample c++ code that cause error C4346 in vs-2009 pro. I
have a "Record" struct within the Database class, and has a "Retrive(int
n)" member function that return "Record*" type. If I have my
implementation code defined within the class then everything works fine.
However if I put it outside the class I get error C4346. I prefer to put
the implementation code outside the class to keep the code clean. Please
help.


Thanks
Jeff





//---------------------------------------------------------------------------

#include <iostream>
#include <string>
using namespace std;
const int Maximum = 100;

//---------------------------------------------------------------------------

// Code-1: Database class definition, has a nested "Record" struct inside
//---------------------------------------------------------------------------

template<typename Object>
class Database {
public:
struct Record {
Object ID;
Record( Object a=Object() ) : ID(a) {}
};

private:
Record items[Maximum];

public:
int Count;
Database() : Count(0) { }

// the following declaration with Code-2 definition will
cause error C4346
Record* Retrieve(const int n);

// however if I replace the code above and those Code-2
with this the error is gone
// Record* Retrieve(const int n) {
// return &items[n];
// }

void Add(const Record& d) {
if ( Count<Maximum ) items[Count++] = d;
}
};

//---------------------------------------------------------------------------

// Code-2: Retrieve() definition with the return type of "Record".
// Receive the following error when trying to compile
// warning C4346: 'Database<Object>::Record' : dependent name is
not a type
// 1> prefix with 'typename' to indicate a type
// error C2143: syntax error : missing ';' before
'Database<Object>::Retrieve'
// error C4430: missing type specifier - int assumed. Note: C++
does not support default-int
// fatal error C1903: unable to recover from previous error(s);
stopping compilation
//---------------------------------------------------------------------------

template<typename Object>
Database<Object>::Record*
Database<Object>::Retrieve(const int n) {
return &items[n];
}


//---------------------------------------------------------------------------

// Main Driver
//---------------------------------------------------------------------------

int main(int argc, char* argv[]) {

typedef Database<int>::Record rec;
Database<int> lists;
lists.Add( rec(12) );
lists.Add( rec(13) );
lists.Add( rec(15) );
lists.Add( rec(18) );
lists.Add( rec(17) );

cout << "Record ID\n";
for(int i = 0; i < lists.Count; i++)
cout << lists.Retrieve(i)->ID << endl;

cout << endl;
system("pause");
return 0;
}

Jeff:

The message tells you what to do:

template<typename Object>
typename Database<Object>::Record* // use typename
Database<Object>::Retrieve(const int n)
{
return &items[n];
}

That said, online Comeau compiles you code as is. (I have never really
understood when you need typename...).

BTW, a better place for standard (non .NET) C++ questions is

microsoft.public.vc.language
 
The message tells you what to do:
template<typename Object>
typename Database<Object>::Record* // use typename
Database<Object>::Retrieve(const int n)
{
return &items[n];
}

That said, online Comeau compiles you code as is. (I have never really
understood when you need typename...).

It's because you could have a specialization of Database in which Record
isn't a struct:

template<>
class Database<int> { void Record() { StartRecording(); } };

In the example given, there's no ambiguity, stuff just doesn't work if
Record isn't a type. But this line could either be a function call or a
cast:

Record(x);

This could either be declaration or multiplication (if Record was a
variable):

Record* p;
BTW, a better place for standard (non .NET) C++ questions is

microsoft.public.vc.language

Right. Cross-posting my comments there.
 
Ben said:
The message tells you what to do:

template<typename Object>
typename Database<Object>::Record* // use typename
Database<Object>::Retrieve(const int n)
{
return &items[n];
}

That said, online Comeau compiles you code as is. (I have never really
understood when you need typename...).

It's because you could have a specialization of Database in which Record
isn't a struct:

template<>
class Database<int> { void Record() { StartRecording(); } };

In the example given, there's no ambiguity, stuff just doesn't work if
Record isn't a type. But this line could either be a function call or a
cast:

Record(x);

This could either be declaration or multiplication (if Record was a
variable):

Record* p;
BTW, a better place for standard (non .NET) C++ questions is

microsoft.public.vc.language

Right. Cross-posting my comments there.

Ben:

You think online Comeau is wrong to accept OP's original code? That would be bad
news, because Comeau is my operational definition of whether a piece of code is
correct or not :-).
 
David Wilkinson said:
Ben said:
The message tells you what to do:

template<typename Object>
typename Database<Object>::Record* // use typename
Database<Object>::Retrieve(const int n)
{
return &items[n];
}

That said, online Comeau compiles you code as is. (I have never really
understood when you need typename...).

It's because you could have a specialization of Database in which Record
isn't a struct:

template<>
class Database<int> { void Record() { StartRecording(); } };

In the example given, there's no ambiguity, stuff just doesn't work if
Record isn't a type. But this line could either be a function call or a
cast:

Record(x);

This could either be declaration or multiplication (if Record was a
variable):

Record* p;
BTW, a better place for standard (non .NET) C++ questions is

microsoft.public.vc.language

Right. Cross-posting my comments there.

Ben:

You think online Comeau is wrong to accept OP's original code? That would
be bad news, because Comeau is my operational definition of whether a
piece of code is correct or not :-).

No, I think that in context, none of the non-typename uses could ever be
allowed (multiplication and casting are statements, and not allowed at file
or namespace scope).

And I misread your comment "never understood when you need typename" as "why
you need typename" and explained why it's needed sometimes. I don't see any
good reason that this should be one of those times (the when).

BTW, you did choose "force instantiation of all templates" when using
tryitout, right?
 
Ben said:
No, I think that in context, none of the non-typename uses could ever be
allowed (multiplication and casting are statements, and not allowed at
file or namespace scope).

And I misread your comment "never understood when you need typename" as
"why you need typename" and explained why it's needed sometimes. I
don't see any good reason that this should be one of those times (the
when).

BTW, you did choose "force instantiation of all templates" when using
tryitout, right?

Ben:

OK, I misread your post.

Yes, I did use "force instantiation of all templates" (it seems to be the default).

I understand that typename is sometimes needed to avoid ambiguity; it's just
that it's hard to figure out when that might be.
 
Hi David,

Thanks for your help. I will try the non-DotNet group. I also found out
putting the "typename" up front fix the error message. By the way is this
ANSI standard or just VS-2008? My textbook (year 2004) sample didn't have
the "typename" in front.

Besides hope you could give me some advice. Is there any benefit switching
to .Net C++? I am interested in audio-visual programming in the long run.
Should I even consider C# or Java for the sack of productivity?

Thanks
Jeff


Ben Voigt said:
The message tells you what to do:

template<typename Object>
typename Database<Object>::Record* // use typename
Database<Object>::Retrieve(const int n)
{
return &items[n];
}

That said, online Comeau compiles you code as is. (I have never really
understood when you need typename...).

It's because you could have a specialization of Database in which Record
isn't a struct:

template<>
class Database<int> { void Record() { StartRecording(); } };

In the example given, there's no ambiguity, stuff just doesn't work if
Record isn't a type. But this line could either be a function call or a
cast:

Record(x);

This could either be declaration or multiplication (if Record was a
variable):

Record* p;
BTW, a better place for standard (non .NET) C++ questions is

microsoft.public.vc.language

Right. Cross-posting my comments there.
 
Besides hope you could give me some advice. Is there any benefit switching
to .Net C++? I am interested in audio-visual programming in the long run.
Should I even consider C# or Java for the sack of productivity?

With '.Net C++' you mean C++/CLI, don't you?
I think that C++/CLI is good as a bridging layer between native code and
managed code.
e.g. if you have some native C++ library and you want to use that from .NET
languages like C#, you could develop a thin C++/CLI layer to connect the
native C++ platform with the .NET managed platform.
But my impression is that C++/CLI is not a first class .NET language; for
example: if you want to build GUIs with WPF, you can use C# or VB.NET, but
not C++/CLI (at least, this is my understanding).
And I think that ASP.NET does not support C++/CLI (only C# or VB.NET).
So, if you want to build something in .NET, I would suggest to consider C#
or VB.NET (if you come from C++, you would prefer C#, because its syntax
looks more natural than VB.NET for someone with a C++/Java background).

About productivity, yes C# offers high productivity to the programmer.
But if you want something that is small and fast, C++ is the way to go.

Giovanni
 
Giovanni said:
With '.Net C++' you mean C++/CLI, don't you?
I think that C++/CLI is good as a bridging layer between native code and
managed code.
e.g. if you have some native C++ library and you want to use that from
.NET languages like C#, you could develop a thin C++/CLI layer to
connect the native C++ platform with the .NET managed platform.
But my impression is that C++/CLI is not a first class .NET language;
for example: if you want to build GUIs with WPF, you can use C# or
VB.NET, but not C++/CLI (at least, this is my understanding).
And I think that ASP.NET does not support C++/CLI (only C# or VB.NET).
So, if you want to build something in .NET, I would suggest to consider
C# or VB.NET (if you come from C++, you would prefer C#, because its
syntax looks more natural than VB.NET for someone with a C++/Java
background).

About productivity, yes C# offers high productivity to the programmer.
But if you want something that is small and fast, C++ is the way to go.

Giovanni

Well, C++/CLI will compile to MSIL just as any other .NET language, so
once it's compiled, it is supported anywhere any .NET assembly might be.
However, I agree that C# would almost always be the better choice for
developing a WinForms or WPF application. You CAN do it with C++/CLI,
but the syntax and IDE just aren't as friendly.
 
Back
Top