Click to See Complete Forum and Search --> : Strange "incomplete type" compile error


wien
February 1st, 2005, 12:31 PM
Hey guys. I am currently experimenting with some different ideas for a Unicode string class, and I came up with a problem I just can't figure out. I hope someone else here can.

The following code has been tested on both VC++ 7.1, GCC 3.3 and Comeau (The online version), and none of them can compile it.
#include <iostream>
#include <cstddef>

struct utf8_tag {};
struct utf16_tag {};
struct utf32_tag {};

namespace detail
{
typedef std::size_t size_type;
typedef unsigned int value_type;
}

template<typename enc>
struct encoding_traits;

template<>
struct encoding_traits<utf32_tag>
{
static detail::value_type get_at_index(detail::size_type index)
{
return index;
}
};

class encoded_string
{
public:
typedef detail::size_type size_type;
typedef detail::value_type value_type;

private:
value_type (*get_at_index)(size_type);

public:
template<typename enc>
encoded_string(enc dummy)
{
get_at_index = &encoding_traits<enc>::get_at_index;
}

value_type operator [] (size_type index)
{
return get_at_index(index);
}
};

int main()
{
encoded_string test(utf32_tag());

std::cout << test[1337] << std::endl;

system("pause");
}Basically all of them complain that the type of test is incomplete. (Although only Comeau is kind enough to let you know that's what the problem is.) Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
Copyright 1988-2003 Comeau Computing. All rights reserved.
MODE:strict errors C++

"ComeauTest.c", line 52: error: expression must be a pointer to a complete object
type
std::cout << test[1337] << std::endl;
^

1 error detected in the compilation of "ComeauTest.c".The really strange bit though, is that if I change "encoded_string test(utf32_tag());" to "encoded_string test = utf32_tag(); Everything suddenly compiles without a hitch.

Anyone care to enlighten me?

RoboTact
February 1st, 2005, 12:51 PM
VC++6 compiled it well (output is "1337").

wien
February 1st, 2005, 12:53 PM
VC++6 compiled it well.Really? That was one compiler I really didn't expect to compile this. Still don't understand what the problem is though...

wien
February 1st, 2005, 01:44 PM
Experimenting a little more, I found out that making a template function that returns the encoding tag fixes the problem, but I still don't understand why the original code is wrong.template<typename enc>
enc make_tag()
{
return enc();
}

...
encoded_string test(make_tag<utf32_tag>());

cilu
February 1st, 2005, 01:55 PM
It also work without problems on VC++7.0 . :sick:

Paul McKenzie
February 1st, 2005, 04:42 PM
The only thing I can possibly imagine is that for a constructor template function, the rules are more explicit, and that the lookup rules as to resolving the template doesn't apply. The following gives no errors for Comeau C++.

#include <iostream>
#include <cstddef>

struct utf8_tag {};
struct utf16_tag {};
struct utf32_tag {};

namespace detail
{
typedef std::size_t size_type;
typedef unsigned int value_type;
}

template<typename enc>
struct encoding_traits;

template<>
struct encoding_traits<utf32_tag>
{
static detail::value_type get_at_index(detail::size_type index)
{
return index;
}
};

class encoded_string
{
public:
typedef detail::size_type size_type;
typedef detail::value_type value_type;

private:
value_type (*get_at_index)(size_type);

public:
encoded_string()
{
}

template<typename enc>
void init(enc dummy)
{
get_at_index = &encoding_traits<enc>::get_at_index;
}

value_type operator [] (size_type index)
{
return get_at_index(index);
}
};

int main()
{
encoded_string test;

test.init(utf32_tag());

std::cout << test[1337] << std::endl;

system("pause");
}

Note that all I did was to construct the object with a non-templated constructor, and then call a templated "init" function.

Regards,

Paul McKenzie

wien
February 1st, 2005, 05:21 PM
The only thing I can possibly imagine is that for a constructor template function, the rules are more explicit, and that the lookup rules as to resolving the template doesn't apply.Hmm.. I think you're on to something here.

The problem seems to come from the fact that the only parameter to the constructor is templated. I tried making a version where the constructor has two parameters, the first of which has a known type (That is, not a templated one), and that works flawlessly in Comeau and VC++. It does however crash sometimes on GCC. (It does compile correctly... strange.)template<typename enc>
encoded_string(float first_dummy, enc dummy)
{
get_at_index = &encoding_traits<enc>::get_at_index;
}

...

encoded_string test(2.0f, utf32_tag());Guess I have to get myself a copy of the standard. There must be something about this in there, since this is consistent behaviour across multiple compilers.