I have a general c++ template programming question...I've tried to setup a class that used a nested template type T, along with variadic template arguments for a constructor of T, to ensure I can add items to a custom container class without any unnecessary heap usage/copy/move operations.
Here is my test container code, using perfect forwarding and std::vector::emplace_back() to create items 'in-place' with little overhead (TemplateContainerTest.h):
#pragma once
#include <vector>
#include <unordered_map>
#include <utility>
template <typename T>
class TemplateContainerTest
{
public:
TemplateContainerTest() = default;
virtual ~TemplateContainerTest() = default;
template<typename... ItemArgs>
void AddItem( ItemArgs&&... itemArgs )
{
m_Container.emplace_back( std::forward<ItemArgs>( itemArgs )... );
}
protected:
template <typename T>
class ItemTracker
{
public:
template<typename... ItemArgs >
ItemTracker( ItemArgs&&... itemArgs ):
m_Item( std::forward<ItemArgs>( itemArgs )... )
{
}
bool m_IsValid = false;
T m_Item;
};
std::vector< ItemTracker<T> > m_Container;
};
And here is some code to exercise the template above (main.cpp):
#include "stdafx.h"
#include <stdint.h>
#include "CNTemplateContainer.h"
class TestItemOfInterest
{
public:
TestItemOfInterest( uint32_t itemVal ):
m_ItemVal( itemVal )
{
}
TestItemOfInterest( TestItemOfInterest && other )
{
m_ItemVal = other.m_ItemVal;
other.m_ItemVal = 0;
}
TestItemOfInterest() = default;
virtual ~TestItemOfInterest() = default;
uint32_t GetVal() { return m_ItemVal; }
protected:
uint32_t m_ItemVal = 0;
};
int _tmain(int argc, _TCHAR* argv[])
{
TemplateContainerTest<TestItemOfInterest> tmpContainer;
tmpContainer.AddItem( 42 );
return 0;
}
Here is the kicker: in Visual Studio 2013, the code above fails to compile with the following error:
templatecontainertest.h(28): error C2664: 'TestItemOfInterest::TestItemOfInterest(const TestItemOfInterest &)' : cannot convert argument 1 from 'TemplateContainerTest<TestItemOfInterest>::ItemTracker<T>' to 'uint32_t'
However, in Visual Studio 2017 it compiles fine. For some reason, the perfect forwarding mechanism of Visual Studio 2013 seems to try to send the 'ItemTracker' into the T() constructor instead of just the arguments from outside. I see that the VS 2017 std::vector::emplace_back signature/implementation changed, but I can't understand why it works now/didn't work before...
Any insight would be appreciated as I don't trust this at all without understanding the underpinning issues...