4

Why following code snippet compile failed on Mac platform using clang++? The sizeof unsigned long and uint64_t is both 8, so I think they are the same type. So why the compile think the Serializer<unsigned long> is abstract?

Because I have define Serializer<uint64_t>, Serializer<int64_t>, Serializer<uint32_t>, Serializer<int32_t>, Serializer<uint16_t>, Serializer<int16_t>, Serializer<uint8_t>, Serializer<int8_t>, is there any way to resolve this issue and avoid define more type like Serializer<unsigned long>?

Following is the error message, both clang++ and g++ give the similar result:

example.cpp:23:31: error: variable type 'Serializer' is an abstract class

Serializer<unsigned long> s;

                          ^ example.cpp:6:25: note: unimplemented 

pure virtual method 'ToString' in 'Serializer'

virtual std::string ToString(const T* val) = 0;

                    ^ 1 error generated.
#include <iostream>
#include <vector>
#include <algorithm>
template <typename T>
class Serializer {
    virtual std::string ToString(const T* val) = 0;
};

template <>
class Serializer<uint64_t> {
public:

    virtual std::string ToString(const int8_t* val) {
        return "";
    }
};

int main(int argc, const char *argv[])
{
    // both of the size is 8 bytes
    std::cout << " size of unsigned long:" << sizeof(unsigned long) << " sizeof uint64_t:" << sizeof(uint64_t);
    // following compile error happen
    Serializer<unsigned long> s;  //<------- Error happen here
    s.ToString(NULL);

    return 0;
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
ZijingWu
  • 3,350
  • 3
  • 25
  • 40
  • 1
    @MichaelChourdakis nope, `sizeof(unsigned long)` must be _at least_ 4. – alter_igel May 20 '19 at 04:31
  • 2
    There can be different types with the same size. maybe `uint64_t` is `unsigned int`, or `unsigned long long`, or something else – M.M May 20 '19 at 04:32
  • The only problem that I see in your code is just not providing virtual destructor for the class templates! I tested every thing was fine on mine (gcc linx). – AKL May 20 '19 at 04:39
  • 2
    "*The `sizeof` `unsigned long` and `uint64_t` is both 8, so I think they are the same type*" - just because they are the same **size** does not guarantee that they are the same **type**. For instance, `uint64_t` could be `unsigned __int64` instead. You need to look at how your particular compiler's headers actually define `uint64_t` – Remy Lebeau May 20 '19 at 04:41
  • @ZijingWu: Which version of Clang/GCC are you using? The latest versions compile this just fine. – P.W May 20 '19 at 04:43
  • Simply try ```std::cout << std::is_same::value;``` by header `````` to be sure! in case of inequity the result should be ```0```. Also try ```Serializer s;```. and if it is OK then do the **quick fix** – AKL May 20 '19 at 04:45
  • @P.W jiayuehuadeMacBook-Pro:src mi$ clang++ --version Apple LLVM version 10.0.0 (clang-1000.10.44.4) Target: x86_64-apple-darwin17.7.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin – ZijingWu May 20 '19 at 04:49
  • @AKL, `std::is_same::value` result is 0 – ZijingWu May 20 '19 at 04:50
  • So apparently they are different try other solution! was ```long``` OK? Also (I am laughing at my self ) what are the circumstances that you could not simply use ```Serializer s;``` ? Give more details maybe we can give you a quick fix! – AKL May 20 '19 at 04:52
  • Also if you want to find out quickly what is type of ```uint64_t``` in human language, simply try ```int i; uint64_t test = &i;``` and read the compile time error code! :) I really don't know any thing more simple than that! It should give an error along the line of ```could not assign value of type int* to ***THE TYPE*** in assignment``` – AKL May 20 '19 at 05:02
  • @AKL, we are writing an util library, which contains `Serializer`, so it can be difficult to let the user use `uint64_t` to replace `unsigned long`. – ZijingWu May 20 '19 at 05:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/193609/discussion-between-akl-and-zijingwu). – AKL May 20 '19 at 05:08

1 Answers1

2

As it was discussed ,by using the compile-time-error-method, the type of uint64_t was found out to be unsigned long long instead of unsigned long. Sizes are the same but their names are different and as every one knows compilers are highly sensitive to and strict about names and rightly so!

This can be fixed without any need to change the libraries or to change the user interface!

Just some where in between headers add something like:

template <>
class Serializer<unsigned long> : public Serializer<uint64_t>{};

Or if user can not access the uint64_t type which is more likely the case:

template <>
class Serializer<unsigned long> : public Serializer<unsigned long long>{};

So now it knows that for unsigned long the specialization is (some what) the same as the case of Serializer<uint64_t> which already has been epecialized!

In addition depending on the definition ofSerializer you might also need to add a constructor to it too like:

template <>
class Serializer<unsigned long> : public Serializer<unsigned long long>{
    Serializer(...DATA...):Serializer<unsigned long long>(...DATA...){}
};

If you don't know what is the definition, this might help:

//for values
class Serializer<unsigned long> : public Serializer<unsigned long long>{
    template<typename ... Ts>
    Serializer(Ts ... Vs):Serializer<unsigned long long>(Vs...){}
};

//for objects
class Serializer<unsigned long> : public Serializer<unsigned long long>{
    template<typename ... Ts>
    Serializer(const Ts& ... Os):Serializer<unsigned long long>(Os...){}
};

Good luck!

AKL
  • 1,367
  • 7
  • 20
  • @ZijingWu If this helped to solve the problem please consider voting it up and/or accepting it! – AKL May 20 '19 at 05:42
  • @ZijingWu thanks for your question and for accepting the answer, but I wished you vote it up too :) – AKL May 21 '19 at 04:58