Template Member Function of Template Class Called from Template Function

template member function of template class called from template function

Try the following code:

template<class T> void g()
{
A<T> a;
a.template f<3>(); // add `template` keyword here
}

According to C++'03 Standard 14.2/4:

When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

Future C++ Standard seems to be still require this keyword according to draft n2857 14.3/4. Some compilers has special mode that allows to compile original code without errors (Comeau compiles it in so called relaxed mode).

Template member function specialization in a template class

Why does this member function specialization get error?

When you instantiate the template class A for example A<std::vector<int>>, the template parameter T is equal to std::vector<int>, not std::vector<T>, and this a specialization case of the function. Unfortunately this can not be done with member functions as mentioned in the comments.



Are there some better solutions?

Yes; In c++17 you could use if constexpr with a trait to check the std::vector, like this.

#include <type_traits> // std::false_type, std::true_type
#include <vector>

// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};

template<typename T>
class A /* final */
{
T mData;

public:
// ...constructor

void print() const /* noexcept */
{
if constexpr (is_std_vector<T>::value) // when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else // for types other than `std::vector<>`
{
std::cout << mData << std::endl;
}
}
};

(See Live Online)

This way you keep only one template class and the print() will instantiate the appropriate part according to the template type T at compile time.


If you don not have access to C++17, other option is to SFINAE the members(Since c++11).

#include <type_traits> // std::false_type, std::true_type, std::enbale_if
#include <vector>

// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};

template<typename T>
class A /* final */
{
T mData;

public:
// ...constructor

template<typename Type = T> // when T == `std::vector<>`
auto print() const -> typename std::enable_if<is_std_vector<Type>::value>::type
{
for (const auto element : mData)
std::cout << element << "\n";
}

template<typename Type = T> // for types other than `std::vector<>`
auto print() const -> typename std::enable_if<!is_std_vector<Type>::value>::type
{
std::cout << mData << std::endl;
}
};

(See Live Online)



What if I have more other data types like self-define vector classes
or matrices? Do I have to define many is_xx_vector?

You can check the type is a specialization of the provided one like as follows. This way you can avoid providing many traits for each type. The is_specialization is basically inspired from this post

#include <type_traits> // std::false_type, std::true_type
#include <vector>

// custom MyVector (An example)
template<typename T> struct MyVector {};

template<typename Test, template<typename...> class ClassType>
struct is_specialization final : std::false_type {};

template<template<typename...> class ClassType, typename... Args>
struct is_specialization<ClassType<Args...>, ClassType> final : std::true_type {};

And the print function could be in c++17:

void print() const /* noexcept */
{
if constexpr (is_specialization<T, std::vector>::value)// when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else if constexpr (is_specialization<T, ::MyVector>::value) // custom `MyVector`
{
std::cout << "MyVector\n";
}
else // for types other than `std::vector<>` and custom `MyVector`
{
std::cout << mData << std::endl;
}
}

(See Live Online)

Template member function specialization of a templated class without specifying the class template parameter

You can use a technique called tag dispatch and replace the template specialisations by function overloads.

template<typename>
struct Tag {};

template <class A>
struct C3
{
void f_impl(Tag<int>) const;
void f_impl(Tag<char>) const;
template<class B>
void f() const {
f_impl(Tag<B>{});
}
};

struct D { static int g(void){ return 999; } };

template <class A>
void C3<A>::f_impl(Tag<int>) const { std::cout<<A::g()+1<<std::endl; }

template <class A>
void C3<A>::f_impl(Tag<char>) const { std::cout<<A::g()+2<<std::endl; }

Then your call site looks exactly as you want:

 C3<D> c3; c3.f<int>();  // expect to see 1000
C3<D> c4; c4.f<char>(); // expect to see 1001

Full example here.

Calling member function template of class template

apply() is a member function template, you need to use the keyword template to tell the compiler that it's a template, when calling it with dependent name. Note the difference between FCT<T,N> and MyFct<float,16>, the former depends on template parameters FCT, T and N, while the later doesn't.

Inside a template definition, template can be used to declare that a dependent name is a template.

e.g.

v1 = FCT<T,N>::template apply<Vec1>();
v2 = FCT<T,N>::template apply<Vec2>();

Unable to call a template member function of a template class from another template class

You should add keyword template:

result.template getSubmatrix<3, 3>(0, 0) = Matrix<3, 3, T>();
// ^^^^^^^^

Without it, compiler will think that < is a comparison operator.

PS. In that case, g++ produces a little more understandable error:

error: invalid operands of types <unresolved overloaded function type> and int to binary operator<

How to add member function of template class only on specific types using type_traits | C++

With SFINAE you can enable/disable a method of a class when the condition tested is related to a template parameter of the method itself. Doesn't works testing a template parameter of the class.

You can solve the problem passing through a method template parameter that is defaulted with the type of the class/struct template parameter.

For example

#include <iostream>
#include <type_traits>

template <typename T>
struct foo
{
template <typename U = T,
std::enable_if_t<std::is_signed_v<U>, bool> = true>
constexpr std::size_t bar ()
{ return sizeof(T); }
};

int main()
{
foo<signed int> fs;
foo<unsigned int> fu;

fs.bar(); // compile
//fu.bar(); // compilation error
}

The problem of this solution is that you can "hijack" it explicating a template parameter

fu.bar(); // compilation error
fu.bar<int>(); // compile

To avoid the hijacking risk, you can (other solutions are possible but this is my preferred) add a non-type variadic template parameter before U

// .......VVVVVVVV  add this to avoid the hijacking problem
template <int ...,
typename U = T,
std::enable_if_t<std::is_signed_v<U>, bool> = true>
constexpr std::size_t bar ()
{ return sizeof(T); }

// ...

fu.bar(); // compilation error
fu.bar<int>(); // compilation error
fu.bar<1, 2, 3, int>(); // compilation error

Template member function in a non-template class - how to define and call

You need to define the function PriorityMap::find in your header file rather than your cpp file.

The problem is that with template functions, no instantiations are created in a given compilation unit unless the function instantiation is actually used in the said unit. The compilation unit in which you define your function is not the same one in which you actually use it, so in your case no instantiations are actually created. Later when it comes to linking the compilation unit(s) in which the function is used no definition is therefore found, so you get a linker error.

If you want to avoid defining the function in the header file then you can explicitly instantiate it in the cpp file in which it is defined. For example:

template void PriorityMap::find(MyClass);

The downside here is that this cpp file will have to know about all the types that will ever have to be used with PriorityMap::find

Invoking non template function from template function

It seems you want to call fun or bar depends on param parameter of foo. If you are using c++17 you can use if constexpr to do that:

class Test
{
public:
template <typename T>
void foo(T param)
{
if constexpr (is_same_v<T,string> || is_same_v<T,const char*>)
fun(param);
else if (is_same_v<T,double>)
bar(param);
}

void fun(string p)
{
std::cout << "string: " << p << std::endl;
}

void bar(double p)
{
std::cout << "double: " << p << std::endl;
}
};

int main() {
Test t;
t.foo("hello");
t.foo(100.0);
return 0;
}

and int i parameter of foo here is no needed, you decide which fun/bar is called based on param type.



Related Topics



Leave a reply



Submit