简体   繁体   中英

ambiguous template specialization in variadic function template

I am trying to write a variadic function template to calculate the byte size of a struct . This is going to be used in a network programming project I am working on. The first step I came up with this without the variadic template that works:

#include <cstdint>
#include <iostream>

struct Position
{
    int32_t x;
    int32_t y;
};

template<typename T>
inline std::size_t sizeT() { return sizeof(T); }

template<>
inline std::size_t sizeT<Position>() { return sizeT<int32_t>() + sizeT<int32_t>(); }
// if I change the definition of Position, I need to remember to change this function

int main(int argc, char* argv[])
{
    std::cout << "int8_t:" << sizeT<int8_t>() << std::endl;
    std::cout << "Position:" << sizeT<Position>() << std::endl;

    return 0;
}

I compiled with g++ 9.3.0 on my Ubuntu 20.04 laptop and it worked fine. However if I try to make it a variadic template then I ran into different compilation errors. The point of this variadic template is to be able to write like the following, so that the implementation doesn't depend on the explicit knowledge of x and y 's types.

Here is bad code #1

#include <cstdint>
#include <iostream>

struct Position
{
    int32_t x;
    int32_t y;
};

template<typename T>
inline std::size_t sizeT() { return sizeof(T); }

template<>
inline std::size_t sizeT<Position>()
{
    return sizeT<decltype(Position::x), decltype(Position::y)>();
}

template<>
inline std::size_t sizeT<Position>() { return sizeT<int32_t>() + sizeT<int32_t>(); }


int main(int argc, char* argv[])
{
    std::cout << "int8_t:" << sizeT<int8_t>() << std::endl;
    std::cout << "Position:" << sizeT<Position>() << std::endl;

    return 0;
}

I got

error: ambiguous template specialization 'sizeT' for 'std::size_t sizeT()

note: candidate are: 'template std::size_t sizeT()'

note: template<class T, class... Ts> std::size_t sizeT()'

Bad code #2. If I put the variadic template at a different location:

#include <cstdint>
#include <iostream>

struct Position
{
    int32_t x;
    int32_t y;
};

template<typename T>
inline std::size_t sizeT() { return sizeof(T); }

template<>
inline std::size_t sizeT<Position>() { return sizeT<int32_t>() + sizeT<int32_t>(); }


template<>
inline std::size_t sizeT<Position>()
{
    return sizeT<decltype(Position::x), decltype(Position::y)>();
}

int main(int argc, char* argv[])
{
    std::cout << "int8_t:" << sizeT<int8_t>() << std::endl;
    std::cout << "Position:" << sizeT<Position>() << std::endl;

    return 0;
}

I got

error: call of overloaded 'sizeT<int8_t>()' is ambiguous

note candidate: 'std::size_t sizeT() [with T=signed char; std::size_t = long unsigned int]'

note candidate: 'std::size_t sizeT() [with T=signed char; Ts={}; std::size_t = long unsigned int]'

error: call of overloaded 'sizeT()' is ambiguous

note candidate: 'std::size_t sizeT() [with T=Position; std::size_t = long unsigned int]'

note candidate: 'std::size_t sizeT() [with T=Position; Ts={}; std::size_t = long unsigned int]'

I kinda understand case #2 but I don't understand #1. How can I achieve this? Thank you so much in advance.

You don't use variadic...

You might do (C++17)

template <typename ... Ts>
constexpr std::size_t sizeT() { return (0 + ... + sizeof(Ts)); }

template <>
constexpr std::size_t sizeT<Position>()
{
    return sizeT<decltype(Position::x), decltype(Position::y)>();
}

Demo

But sizeT<Position, Position> would return 2 * sizeof(Position) instead of 2 * sizeT<Position> (which are identical here).

You might do instead:

template <typename... Ts>
struct tag{};

template <typename T>
constexpr std::size_t sizeT(tag<T>) { return sizeof(T); }

template <typename ... Ts>
constexpr std::size_t sizeT(tag<Ts...>) { return (0 + ... + sizeT(tag<Ts>())); }

template <typename ... Ts>
constexpr std::size_t sizeT(tag<Ts>...) { return (0 + ... + sizeT(tag<Ts>())); }

constexpr std::size_t sizeT(tag<Position>)
{
    return sizeT(tag<decltype(Position::x), decltype(Position::y)>());
}

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM