problem with testing a function

V

Vladimir Jovic

Hello,

I tried to compile an example from the "c++ templates - the complete
guide", and got an error.
Can anyone explain why error appeared? And how to fix it?

Here is the example :

// CODE START
#include <iostream>

template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(NULL) ) == 1 ) };
enum { No = !Yes };
};

void hehe(int , double , const char*[])
{
}

class A
{
};

int main()
{
std::cout << "void hehe(int , double , const char*[]) is a function : "
<< IsFunctionT< &hehe >::Yes << std::endl;
std::cout << "class A is a function : "
<< IsFunctionT< A >::Yes << std::endl;
}
// CODE END

The error is :
ops.cpp: In function ‘int main()’:
ops.cpp:27: error: type/value mismatch at argument 1 in template
parameter list for ‘template<class T> class IsFunctionT’
ops.cpp:27: error: expected a type, got ‘hehe’
ops.cpp: At global scope:
ops.cpp: In instantiation of ‘IsFunctionT<A>’:
ops.cpp:29: instantiated from here
ops.cpp:12: error: invalid application of ‘sizeof’ to incomplete type
‘IsFunctionT<A>’



I tried this :
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T > ) == 1 ) }; <<<<<<<<<
enum { No = !Yes };
};

and even this fails with next error message:
ops.cpp:31: instantiated from here
ops.cpp:12: error: invalid application of ‘sizeof’ to incomplete type
‘IsFunctionT<A>’
 
V

Vladimir Jovic

Sorry for not posting the minimal example to show the problem. This is
the minimal example that demonstrates the problem :

// CODE START
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(0) ) == 1 ) };
enum { No = !Yes };
};

int main()
{
}
// CODE END

the error is :
[vladimir@juniper data_create]$ g++ -ansi -W -Wall -pedantic ops.cpp
ops.cpp:10: error: expected primary-expression before ‘>’ token
[vladimir@juniper data_create]$
 
P

Paul Bibbings

Vladimir Jovic said:
Sorry for not posting the minimal example to show the problem. This is
the minimal example that demonstrates the problem :

// CODE START
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(0) ) == 1 ) };
enum { No = !Yes };
};

int main()
{
}
// CODE END

the error is :
[vladimir@juniper data_create]$ g++ -ansi -W -Wall -pedantic ops.cpp
ops.cpp:10: error: expected primary-expression before ¡®>¡¯ token
[vladimir@juniper data_create]$

I can reproduce this error only with versions of GCC prior to the
4.4 series:

10:52:15 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $g++-4 --version && g++-4 -ansi -W
-Wall -pedantic ops.cpp
g++-4 (GCC) 4.3.4 20090804 (release) 1
Copyright (C) 2008 Free Software Foundation, Inc.

ops.cpp:11: error: expected primary-expression before ¡®>¡¯ token

10:54:09 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-g++-4.4.1 -ansi -W
-Wall -pedantic ops.cpp

10:54:38 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $

with similar failure for 3.3.4 and similar success with both gcc-4.4.3
and 4.5.0.

What version are you using?

Regards

Paul Bibbings
 
V

Vladimir Jovic

Paul said:
Vladimir Jovic said:
Sorry for not posting the minimal example to show the problem. This is
the minimal example that demonstrates the problem :

// CODE START
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(0) ) == 1 ) };
enum { No = !Yes };
};

int main()
{
}
// CODE END

the error is :
[vladimir@juniper data_create]$ g++ -ansi -W -Wall -pedantic ops.cpp
ops.cpp:10: error: expected primary-expression before ¡®>¡¯ token
[vladimir@juniper data_create]$

I can reproduce this error only with versions of GCC prior to the
4.4 series:

Does it mean it was a bug in gcc, and is fixed now?
Is the original example breaking rules of c++ standard?

I modified the example to this:

//////
#include <iostream>
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename U> static One test(...);
template<typename U> static Two test(U (*)[1]);
public:
enum { Yes = sizeof(test<T>(0)) == 1 };
enum { No = !Yes };
};
class A
{
};
int main()
{
std::cout<<"IsFunction< foo >::Yes = " << (int) IsFunctionT< void
(*)(double,float,char*[]) >::Yes << std::endl;
std::cout<<"IsFunction< A >::Yes = " << (int) IsFunctionT< A >::Yes
<< std::endl;
}
//////

and it compiles fine, but the output is wrong:
IsFunction< foo >::Yes = 0
IsFunction< A >::Yes = 0

Modifying the problematic line to this:
enum { Yes = sizeof(test<T>((T*)0)) == 1 };
the output changes to this:
IsFunction< foo >::Yes = 1
10:52:15 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $g++-4 --version && g++-4 -ansi -W
-Wall -pedantic ops.cpp
g++-4 (GCC) 4.3.4 20090804 (release) 1
Copyright (C) 2008 Free Software Foundation, Inc.

ops.cpp:11: error: expected primary-expression before ¡®>¡¯ token

10:54:09 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-g++-4.4.1 -ansi -W
-Wall -pedantic ops.cpp

10:54:38 Paul Bibbings@JIJOU
/cygdrive/d/CPPProjects/CLCPP $

with similar failure for 3.3.4 and similar success with both gcc-4.4.3
and 4.5.0.

What version are you using?

Sorry, forgot to post that :
g++ -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
--infodir=/usr/share/info
--with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap
--enable-shared --enable-threads=posix --enable-checking=release
--with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions
--enable-languages=c,c++,objc,obj-c++,java,fortran,ada
--enable-java-awt=gtk --disable-dssi --enable-plugin
--with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre
--enable-libgcj-multifile --enable-java-maintainer-mode
--with-ecj-jar=/usr/share/java/eclipse-ecj.jar
--disable-libjava-multilib --with-cpu=generic --build=i386-redhat-linux
Thread model: posix
gcc version 4.3.0 20080428 (Red Hat 4.3.0-8) (GCC)
 
Ö

Öö Tiib

Paul said:
Sorry for not posting the minimal example to show the problem. This is
the minimal example that demonstrates the problem :
// CODE START
template<typename T>
class IsFunctionT {
  private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template< typename U > static One test(...);
    template< typename U > static Two test(U (*)[1]);
  public:
    enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(0) ) == 1 ) };
    enum { No = !Yes };
};
int main()
{
}
// CODE END

This is valid code and refusing compiler is perhaps buggy.
the error is :
[vladimir@juniper data_create]$ g++ -ansi -W -Wall -pedantic  ops.cpp
ops.cpp:10: error: expected primary-expression before ‘>’ token
[vladimir@juniper data_create]$
I can reproduce this error only with versions of GCC prior to the
4.4 series:

Does it mean it was a bug in gcc, and is fixed now?

Yes that particular bug is likely fixed or narrowed down so your
example does not trigger it.
Is the original example breaking rules of c++ standard?

Yes. 14.3.1/1 "A template-argument for a template-parameter which is a
type shall be a type-id."

Plain and simple? Yours seemed a function pointer not type-id.
 
I

Ian Collins

Hello,

I tried to compile an example from the "c++ templates - the complete
guide", and got an error.
Can anyone explain why error appeared? And how to fix it?

Here is the example :

// CODE START
#include <iostream>

template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(NULL) ) == 1 ) };
enum { No = !Yes };
};

void hehe(int , double , const char*[])
{
}

class A
{
};

int main()
{
std::cout << "void hehe(int , double , const char*[]) is a function : "
<< IsFunctionT< &hehe >::Yes << std::endl;
std::cout << "class A is a function : "
<< IsFunctionT< A >::Yes << std::endl;
}

Adding a wrapper function:

template<typename T>
IsFunctionT<T> isFunction( T ) { return IsFunctionT<T>(); }

And calling with

isFunction(hehe).Yes

gets the code to compile, but the result is still 0 0.
 
P

Paul Bibbings

Vladimir Jovic said:
Paul said:
Vladimir Jovic said:
Sorry for not posting the minimal example to show the problem. This is
the minimal example that demonstrates the problem :

// CODE START
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(0) ) == 1 ) };
enum { No = !Yes };
};

int main()
{
}
// CODE END

the error is :
[vladimir@juniper data_create]$ g++ -ansi -W -Wall -pedantic ops.cpp
ops.cpp:10: error: expected primary-expression before ¡®>¡¯ token
[vladimir@juniper data_create]$

I can reproduce this error only with versions of GCC prior to the
4.4 series:

Does it mean it was a bug in gcc, and is fixed now?
Is the original example breaking rules of c++ standard?

I would say that the former, certainly. I do not have the book by
Vandevoorde and Josuttis in which this example evidently appears, but I
would find it hard to believe that their code would be anything but
standard compliant. Having said that, I haven't checked it out in the
GCC bug lists.
I modified the example to this:

//////
#include <iostream>
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename U> static One test(...);
template<typename U> static Two test(U (*)[1]);
public:
enum { Yes = sizeof(test<T>(0)) == 1 };
enum { No = !Yes };
};
class A
{
};
int main()
{
std::cout<<"IsFunction< foo >::Yes = " << (int) IsFunctionT< void
(*)(double,float,char*[]) >::Yes << std::endl;
std::cout<<"IsFunction< A >::Yes = " << (int) IsFunctionT< A >::Yes
<< std::endl;
}
//////

and it compiles fine, but the output is wrong:
IsFunction< foo >::Yes = 0
IsFunction< A >::Yes = 0

I would say that the output is correct here. Note that:

void (*)(double, float, char*[])

in *not* a function type, but rather a pointer to function type.

If you try this again with:

void (double, float, char*[])

you will find that the results should match what you expect.
Modifying the problematic line to this:
enum { Yes = sizeof(test<T>((T*)0)) == 1 };
the output changes to this:
IsFunction< foo >::Yes = 1
IsFunction< A >::Yes = 1

This simply breaks what the code is trying to achieve, essentially.


Regards

Paul Bibbings
 
P

Paul Bibbings

Ian Collins said:
Hello,

I tried to compile an example from the "c++ templates - the complete
guide", and got an error.
Can anyone explain why error appeared? And how to fix it?

Here is the example :

// CODE START
#include <iostream>

template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template< typename U > static One test(...);
template< typename U > static Two test(U (*)[1]);
public:
enum { Yes = ( sizeof( IsFunctionT< T >::test< T >(NULL) ) == 1 ) };
enum { No = !Yes };
};

void hehe(int , double , const char*[])
{
}

class A
{
};

int main()
{
std::cout << "void hehe(int , double , const char*[]) is a function : "
<< IsFunctionT< &hehe >::Yes << std::endl;
std::cout << "class A is a function : "
<< IsFunctionT< A >::Yes << std::endl;
}

Adding a wrapper function:

template<typename T>
IsFunctionT<T> isFunction( T ) { return IsFunctionT<T>(); }

And calling with

isFunction(hehe).Yes

gets the code to compile, but the result is still 0 0.

This is because the type of hehe, according to the rules of template
argument deduction, is adjusted using a function to pointer to function
conversion, instantiating:

IsFunctionT<void (*)(int, double, char const**)>
isFunction<void (*)(int, double, char const**)>(void (*)(int, double,
char const**))

and we no longer have a function type, hence the test fails.

Regards

Paul Bibbings
 
V

Vladimir Jovic

Paul said:
I would say that the former, certainly. I do not have the book by
Vandevoorde and Josuttis in which this example evidently appears, but I
would find it hard to believe that their code would be anything but
standard compliant. Having said that, I haven't checked it out in the
GCC bug lists.

Yes, I found it very strange that I can not compile the example in the OP.
and it compiles fine, but the output is wrong:
IsFunction< foo >::Yes = 0
IsFunction< A >::Yes = 0

I would say that the output is correct here. Note that:

void (*)(double, float, char*[])

in *not* a function type, but rather a pointer to function type.

If you try this again with:

void (double, float, char*[])

you will find that the results should match what you expect.

Yes, that works. Thanks

The complete example is :

#include <iostream>
template<typename T>
class IsFunctionT {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename U> static One test(...);
template<typename U> static Two test(U (*)[1]);
public:
enum { Yes = sizeof(test<T>(0)) == 1 };
enum { No = !Yes };
};
class A
{
};
int main()
{
std::cout<<"IsFunction< foo >::Yes = " << (int) IsFunctionT< void
(double,float,char*[]) >::Yes << std::endl;
std::cout<<"IsFunction< A >::Yes = " << (int) IsFunctionT< A >::Yes
<< std::endl;
}


btw I contacted autors, and their response was very fast. What I
triggered was a bug in gcc 4.3, which is fixed in the later version.
 
P

Paul Bibbings

Vladimir Jovic said:
Yes, I found it very strange that I can not compile the example in the
OP.

I haven't got the book by Vandevoorde and Josuttis (though I really
should get myself a copy), but this thread did lead me to their example
code on the internet (http://www.josuttis.de/tmplbook/) where I was
surprised to find that, in one place, there does appear to be a section
of code that, IMHO, fails to compile through being non-standard. (I
appreciate that the book, and code, was written in 2002, so it's
possible that there was a change between C++98 and C++03 that might have
broken the original code.)

In basics/stack7decl.hpp they have this class template
(http://www.josuttis.de/tmplbook/basics/stack7decl.hpp.html):

template <typename T,
template <typename ELEM> class CONT = std::deque >
class Stack {
private:
CONT<T> elems; // elements

public:
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};

This code is supplemented with appropriate definitions and used with
implicit instantiations through, for example:

Stack<int> intStack; // (in basics/stack7test.cpp)

This is the kind of thing that I remember compiled without problem using
some thing like gcc-4.3.4 or earlier. However, it would not compile
with more recent versions, and I believe these newer versions are
correct.

The problem is that the type std::deque has *two* template parameters,
the second being the allocator which defaults to std::allocator<T> (on
std::deque<T>). I believe (though, of course, I'm open to being
corrected) that this second template parameter cannot be ignored in the
above code, even though a default is provided. I think this needs to be
something along the lines of:

template< typename T,
typename Alloc = std::allocator< T >,
template< typename ELEM, typename Alloc> class CONT =
std::deque >
class Stack {
private:
CONT< T, Alloc > elems;

// ... etc.
};

Certainly gcc-4.4.3 requires this form of adjustment in order to enable
instantiation using Stack<int>, etc.

Regards

Paul Bibbings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top