André Ferreira
André Ferreira

Reputation: 115

Variadic template argument list with changing return type

I am trying to make a templated variadic with a changing return type. If the number of arguments is 1 then it should return a pointer to the only argument, otherwise it should return a tuple of pointer of the argument:

int var = 0;
A *ptr_A = foo<A>(var);
auto *[ptr_A, ptr_B] = foo<A, B>(var);

and this is the code i have so far

template<typename T>
T* AddComp(EntityId entityID)
{
    componentPool<T>* pool = GetOrCreatePool<T>();
    return pool->Create(entityID);
}

template <typename... Args>
decltype(auto) AddComponent(EntityId entityID)
{
    if constexpr (sizeof...(Args) == 1)
    {
        return AddComp <Args>(entityID);
    }
    else
    {
        return std::tuple<decltype(AddComponent<Args>({}))... > {AddComponent<Args>(entityID)...};
    }
}

But i am getting several errors:

In case of A *ptr_A = foo<A>(var); VS says that he cannot convert from void to A*, which says that decltype(auto) is somehow becoming void

And in return AddComp <Args>(entityID); VS says that Args parameter pack must be expanded. Do i still need to somehow expand Args even if its a single parameter?

Thank you!

Edit:

As asked i am providing a minimal example

using EntityId = size_t;

class A
{
public:

int a;
};

class B
{
public:

int b;
};

class componentsManager
{
    
public:

template<typename T>
T* AddComp(EntityId entityID)
{
    return new T();
}

template <typename... Args>
decltype(auto) AddComponent(EntityId entityID)
{
    if constexpr (sizeof...(Args) == 1)
    {
        return AddComp <Args>(entityID);
    }
    else
    {
        return std::tuple<decltype(AddComponent<Args>({}))... > {AddComponent<Args>(entityID)...};
    }
}
    
};

componentsManager m_manager;
EntityId id;

A *ptr_A1 = m_manager.AddComponent <A>(id);
auto *[ptr_A2, ptr_B] =  m_manager.AddComponent<A, B>(id);// This will only compile in c++17 i believe, i am using c++14

Edit2:

Error i get in VS 2019 VSError

Upvotes: 1

Views: 180

Answers (1)

Igor Tandetnik
Igor Tandetnik

Reputation: 52621

The straightforward

if constexpr (sizeof...(Args) == 1)
{
    return AddComp<Args...>(entityID);
}

appears to work just fine. Clang demo, MSVC demo


Here's a solution that works with C++14:

template <typename T>
decltype(auto) AddComponent(EntityId entityID)
{
  return AddComp<T>(entityID);
}

template <typename... Args>
decltype(auto) AddComponent(
    std::enable_if_t<(sizeof...(Args) > 1), EntityId> entityID)
{
    return std::tuple<decltype(AddComponent<Args>({}))...>{
        AddComponent<Args>(entityID)...};
}

Demo

Upvotes: 1

Related Questions