I am trying to use a templated function to return the default value for a parameter in the constructor of a template class. The template parameters for the function are also template parameters for the class. I provided an example below.
Background The example shows the exact use case and dependencies as they also occur in my application. Class X is actually a quite big class which manages a big data block which is split into smaller blocks. Class Helper is a memory manager which allocates and frees memory in the size of the smaller blocks. In reality, the GetHelper function would try to deduce some constructor parameters of Helper at runtime, so this is why I used this design.
Actual question When both macros USE_NS and SHOW_ERROR are defined, the code doesn´t compile, giving an error C2783 could not deduce template argument at line 66. This is where I try to initialize a constructor parameter with the templated function GetHelper (providing the template parameters!). Remember, GetHelper is from a different namespace than the class X. Please also mind, that in line 72 the same function call is used, to initialize the Helper object inside the ctor body. What is wrong? Is there a solution or workaround?
I am using Visual Studio 2008 Pro, and boost 1.47.
#include <iostream>
#include <boost/shared_ptr.hpp>
// 1 means macro is defined
// USE_NS 1 and SHOW_ERROR 1 -> Compileerror
// USE_NS 0 and SHOW_ERROR 1 -> Works, Output: 8 and 16.5
// USE_NS 1 and SHOW_ERROR 0 -> Works, Output: 3
// USE_NS 0 and SHOW_ERROR 0 -> Works, Output: 3
#define USE_NS
#define SHOW_ERROR
#ifndef USE_NS
#define NH
#define NX
#endif
#ifdef USE_NS
namespace NH
{
#endif
template< typename TNumAtH, size_t TSizeAtH>
class Helper
{
public:
TNumAtH* x;
Helper()
{
x = new TNumAtH[TSizeAtH];
x[0] = static_cast< TNumAtH >( 8 );
}
~Helper()
{
delete [] x;
}
};
template <typename TNumAtF, size_t TSizeAtF >
boost::shared_ptr< Helper< TNumAtF, TSizeAtF > > GetHelper()
{
return boost::shared_ptr< Helper< TNumAtF,TSizeAtF > > ( new Helper< TNumAtF, TSizeAtF >() );
}
#ifdef USE_NS
}
namespace NX
{
#endif
template< typename TNumAtX, size_t TSize >
class X
{
public:
boost::shared_ptr< NH::Helper< TNumAtX, TSize > > a;
#ifdef SHOW_ERROR
//this produces an error if namespace are used, if no namespaces are used
//NH is reduced to a blank (see macros at line 17 and 18
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h = NH::GetHelper< TNumAtX, TSize >() );
#endif
X( TNumAtX firstElem )
{
//this works with namespaces and without namespaces
a = NH::GetHelper< TNumAtX, TSize >();
a->x[0] = firstElem;
}
TNumAtX GetNum()
{
return a->x[0];
}
};
#ifdef SHOW_ERROR
template< typename TNumAtX, size_t TSize >
X<TNumAtX, TSize>::
X( boost::shared_ptr< NH::Helper< TNumAtX, TSize > > h ) : a( h )
{
}
#endif
#ifdef USE_NS
}
#endif
int main( int argc, char** argv )
{
std::cout << "Hello at TestTemplateFunction" << std::endl;
//use case one
#ifdef SHOW_ERROR
NX::X<int, 5> x1;
#else
NX::X<int, 5> x1( 3 );
#endif
std::cout << "Use case 1: " << x1.GetNum() << std::endl;
//use case two
#ifdef SHOW_ERROR
typedef float T;
size_t const N = 9;
boost::shared_ptr< NH::Helper<T, N> > h( new NH::Helper<T, N> );
h->x[0] = 16.5f;
NX::X<T, N> x2( h );
std::cout << "Use case 2: " << x2.GetNum() << std::endl;
#endif
std::cout << "Hit the any key" << std::endl;
getchar();
return 0;
}
and here is the CMakeLists.txt file
PROJECT(TestTemplateFunction)
CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
FIND_PACKAGE( BOOST )
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
ADD_EXECUTABLE( TestTemplateFunction main.cpp )
Edit: The compile error
main.cpp(65) : error C2783: 'boost::shared_ptr<NH::Helper<TNumAtH,TSizeAtH>> NH::GetHelper(void)' : could not deduce template argument for 'TNumAtF'
main.cpp(44) : see declaration of 'NH::GetHelper'
main.cpp(65) : error C2783: 'boost::shared_ptr<NH::Helper<TNumAtH,TSizeAtH>> NH::GetHelper(void)' : could not deduce template argument for 'TSizeAtF'
main.cpp(44) : see declaration of 'NH::GetHelper'