I am trying to implement a friend template function over a normal class.
fren.h
#include <iostream>
namespace sn{
class Fren{
private:
int x;
public:
Fren(int y):x(y){
}
template<typename B>
friend void getValue(B& asd);
};
template<typename B>
void getValue(B& asd);
}
fren.cpp
#include "fren.h"
namespace sn{
template<typename B>
void getValue(B& asd){
std::cout<<asd.x<<std::endl;
}
}
main.cpp
#include "fren.h"
int main() {
sn::Fren f(10);
sn::getValue(f);
return 0;
}
I am trying to get the private value x of Fren.
But i get the "undefined reference to" error.
First off, unless there is a solid reason for otherwise, most of this belongs in a single header file. See "Why can templates only be implemented in the header file?" for why.
That said, if you want to use explicit instantiation for your function template, you can. Note the following, which is also more restrictive than your friending. This code only friends the function templates with matching template arguments to Fren:
func.h
#ifndef SAMPLE_FUNC_H
#define SAMPLE_FUNC_H
namespace sn
{
template<class T>
struct Fren;
template<class T>
void getValue(const Fren<T>& s);
template<class T>
struct Fren
{
friend void getValue <>(const Fren<T>&);
Fren() : x(42) {}
private:
int x;
};
} // namespace
#endif
func.cpp
#include "func.h"
#include <iostream>
namespace sn
{
template<class T>
void getValue(const Fren<T>& s)
{
std::cout << s.x << ':' << __PRETTY_FUNCTION__ << '\n';
}
// explicit instantiation here
template void getValue <int> (const Fren<int>&);
}
main.cpp
#include <iostream>
#include <string>
#include "func.h"
int main()
{
sn::Fren<int> s;
sn::getValue(s);
}
Output
42:void sn::func(const S<T> &) [T = int]
Compiled with Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
In short, your code appears to be missing the actual explicit instantiation.
Related
This question already has answers here:
How to conditionally add a function to a class template?
(5 answers)
Closed 2 years ago.
I have a class template defined as follow
template<typename T>
class A
{
T t_;
// void f();
};
My question is how to add the f() method only if the type T is integer without compilation error.
int main()
{
A<int> a; // OK
A<string> b; // OK
}
Example :
#include <type_traits>
#include <new>
#include <iostream>
#include <string>
template <typename T>
struct Foo
{
T t;
template <typename..., typename U = T>
std::enable_if_t<std::is_same_v<T, int>> say_hello() { std::cout << "Hello"; }
};
int main()
{
Foo<int>();
Foo<double>();
}
Error C2938 'std::enable_if_t<false,void>' : Failed to specialize alias template
Thank you.
You can enable specific functions using type_traits and SFINAE:
#include <iostream>
#include <string>
#include <type_traits>
template<typename T>
class A
{
public:
template<typename U = T, std::enable_if_t<std::is_integral_v<U>, int> = 0>
void f() {
std::cout << "int " << t_ << '\n';
}
private:
T t_;
};
int main() {
A<int> a;
a.f();
A<std::string> s;
// s.f(); // error: no member named 'f' in 'A<std::__cxx11::basic_string<char> >'
}
If you have many integer specific functions you can put them in a class of its own and inherit that class only if T is integral.
#include <iostream>
#include <string>
#include <type_traits>
template<typename Atype>
class int_functions {
public:
Atype* This() { return static_cast<Atype*>(this); }
void f() {
std::cout << "int " << This()->t_ << '\n';
}
};
template<typename Atype>
class non_int_functions {
};
template<typename T>
class A : public std::conditional_t<std::is_integral_v<T>, int_functions<A<T>>,
non_int_functions<A<T>>>
{
friend std::conditional_t<std::is_integral_v<T>, int_functions<A<T>>,
non_int_functions<A<T>>>;
public:
private:
T t_;
};
I would like to have in my library a template function func such that the user can overload it with its own types. The problem is that my type system is of the form
T := A<T>, B<T>, C
As such, template<class T> void func(A<T>); needs template<class T> void func(B<T>); if it is specialised with T = B<C>. Reciprocally, if we instantiate func(B<T>) with T = A<C>, the B<T> specialisation needs the A<T> specialisation.
The problem until here could be solved declaring the template functions in some common header.
What I don't know how to approach is how to make this type system extensible. I would like that the user can define her own type template<class T> class D<T>; and implement her own template<class T> void func(D<T>);. In this case, I don't know how the user could forward declare her type so that in the specialisation A<D<C>> the function void func(A<T>); is able to find void func(D<T>);.
Is there any standard way of doing this?
Edit minimal working example of the problem:
// in A.hpp
namespace ns {
template<class T> struct A { T t; };
template<class T>
void fun (A<T> a) { fun(a.t); }
}
// B.hpp
namespace ns {
template<class T> struct B { T t; };
template<class T>
void fun (B<T> b) { fun(b.t); }
// C.hpp
#include <iostream>
namespace other {
template<class T>
struct C {};
}
namespace ns {
template<class T>
void fun(other::C<T> c) { std::cout << "C" << std::endl; }
}
// main.cpp
#include "A.hpp"
#include "B.hpp"
#include "C.hpp"
namespace ns {
void f () {
fun(A<B<other::C<int>>>());
}
}
int main () {
ns::f();
}
This example doesn't compile. It just compiles if we reorder the includes in main.cpp as
#include "C.hpp"
#include "B.hpp"
#include "A.hpp"
Now, this is clearly a hack. With this design the user will not be able to instantiate both A<B<C<int>>> and B<A<C<int>>>. A solution to this would be to forward declare A and B in some other template and include it in both A.hpp and B.hpp. The problem now comes when you try to let the user of the library define her own types. If the user of the library defines her own type template<class T> class D;, she cannot forward declare, and then, if she tries to instantiate A<D<C<int>>>, the compilation will fail.
In this example the namespace other represents a namespace over which I don't have control, and C represents a preexisting class in some other library. This can be thought as some boost class or similar. The ns namespace is the one that my library defines.
What about if fun() is a static method in a template class?
So you can partial specialize the class?
I mean something like
// 000.h
#ifndef h_000__h
#define h_000__h
namespace ns
{
template <typename T>
struct foo;
}
#endif
// 001.h
#ifndef h_001__h
#define h_001__h
#include <iostream>
#include "000.h"
namespace ns
{
template<class T>
struct A
{ T t; };
template <typename T>
struct foo<A<T>>
{
static void fun (A<T> a)
{ std::cout << "A<T> fun" << std::endl; foo<T>::fun(a.t); }
};
}
#endif
// 002.h
#ifndef h_002__h
#define h_002__h
#include <iostream>
#include "000.h"
namespace ns
{
template <typename T>
struct B
{ T t; };
template <typename T>
struct foo<B<T>>
{
static void fun (B<T> a)
{ std::cout << "B<T> fun" << std::endl; foo<T>::fun(a.t); }
};
}
#endif
// 003.h
#ifndef h_003__h
#define h_003__h
#include <iostream>
#include "000.h"
namespace other
{
template <typename T>
struct C
{ };
}
namespace ns
{
template <typename T>
struct foo<other::C<T>>
{
static void fun (other::C<T> a)
{ std::cout << "C<T> fun" << std::endl; }
};
}
#endif
// main.cpp
#include "001.h"
#include "002.h"
#include "003.h"
namespace ns
{
void f ()
{
using type = A<B<other::C<int>>>;
foo<type>::fun(type{});
}
}
int main ()
{
ns::f(); // print A<T> fun \n B<T> fun \n C<T> fun \n
}
I'm sure there is a very easy answer, but I can't figure it out. I have written a templated class, but I want to pass that class by reference in a class function that isn't templated. Heres what I have. I get a bunch of errors. All I need to do is figure how to format the way to insert templated class into function, but I'm at a lost. Thank you and sorry if the code doesn't really help you out.
#include <iostream>
using namespace std;
template <typename T>
class Foo {
public:
Foo();
insert(const T& Item)
//And other function, just examples
};
class noFoo(){
void test(Foo <T>& foo);
int i;
int j;
int k
};
template <typename T>
void noFoo::test(Food <T>& foo)}
cout << "hi";
}
int main() {
Foo<char> wr;
test(wr);
return 0;
}
Make test a function template. I also corrected loads of syntax errors for you (class noFoo()?), removed unnecessary code, and ran clang-format for indentation.
#include <iostream>
template <typename T>
class Foo {};
class noFoo
{
public:
template <typename T>
void test(Foo<T> &);
};
template <typename T>
void noFoo::test(Foo<T> &)
{
std::cout << "hi\n";
}
int main()
{
Foo<char> wr;
noFoo{}.test(wr);
}
Since your question is tagged d, here the same code in D.
import std.stdio;
class Foo(T) {};
class noFoo
{
public:
void test(T)(Foo!(T))
{
writeln("hi");
}
};
void main()
{
auto wr = new Foo!char;
(new noFoo).test(wr);
}
I have a template API function in my class called template<typename T> T Get(/*stuff*/);. My source file implements this function for a certain list of T types. If the user wants to use a type that I have not implemented, then I want the result to be a compile error, and not a linker error. I don't care much about the compile message yet. Here's what I've got so far:
MyClass.h
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct API
{
static T Get(const T&);
};
template<typename T> struct Implemented {};
API_TYPE(bool);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
MyClass.cpp
#include "MyClass.h"
namespace MyClassAPI
{
template<typename T> T API<T>::Get(const T& t) { return t; }
//template struct API<bool> //Why do I need this?
}
main.cpp
#include "MyClass.h"
#include <iostream>
#include <cassert>
using namespace std;
// Main File
int main() {
MyClass c;
cout << "Getting true: " << c.Get(true) << endl;
return 0;
}
So my question is about a line in MyClass.cpp. Why do I need to replicate the API<bool> explicit declaration in the source file with template struct API<bool>;? Shouldn't it know to expand the template function definition from the header file's declaration when Implemented<bool> : public API<bool> inherits from it?
Also, is there a way to do this without declaring my accepted type list twice?
Error without the line:
g++ -Wfatal-errors -Werror -std=c++11 -g -O0 -Wall -c MyClass.cpp -o MyClass.o
g++ -Wfatal-errors -Werror -std=c++11 -g -O0 -Wall test.cpp MyClass.o -o test
/tmp/ccVxp4F3.o: In function `bool MyClass::Get<bool>(bool const&) const':
MyClass.h:25: undefined reference to `MyClassAPI::API<bool>::Get(bool const&)'
collect2: error: ld returned 1 exit status
make: *** [test] Error 1
The problem with your template is you're defining it's members in a separate translation unit, hence they are not visible to main.cpp, and C++ does not support separate translation of templates.
When you use template struct API<bool>; you ask the compiler to explicitly instantiate API<T> for T = bool. However, when doing so, you should also let the other translations units know that the instantiation takes place elsewhere by having a similar directive in the header file with template declaration:
extern template struct API<bool>;
Otherwise, move the definition of Get to the header file or include .cpp file in the header file (not recommended) and rely on the compiler to instantiate template members for you.
As about limiting the list of viable template parameters, I suggest an approach based on template metaprogramming.
First we'll define some facility for checking whether a type belongs to a list of types, let's call it is_in<DesiredType, ViableTypes...>. It will accept as template parameters a type T to look for and a list of types InTypes... for search, and provide result by a static boolean member available at compile-time.
It is implemented as a simple recursive algorithm on a list, checking each element of the list against DesiredType until DesiredType is found or the end of list is met:
#include <type_traits>
template<typename...> struct is_in;
template<typename T, typename InType, typename... InTypes> struct is_in<T, InType, InTypes...> {
static constexpr bool value = std::is_same_t<T, InType> ||
is_in<T, InTypes...>::value;
}
template<typename T> struct is_in<T> {
static constexpr bool value = false;
}
Now, having is_in, we can just use static_assert and explicitly specify viable types for a template:
template<typename T> struct API
{
// Only allow API<bool> and API<int>
static_assert(is_in<T, bool, int>::value, "invalid template type for API<T>");
static T Get(const T&);
};
You almost have it there.
You need update MyClass.h to provide explicit instantiations of couple of functions and implement them in MyClass.cpp.
In the .h file, add:
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
In the .cpp file, add:
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
// Add whatever logic that makes sense for this type.
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
// Add whatever logic that makes sense for this type.
return 10*in;
}
}
Here's a single file version of working code:
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct Implemented;
template<typename T> struct API
{
static T Get(T const&);
};
API_TYPE(int);
API_TYPE(double);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
#include <iostream>
int main()
{
MyClass a;
std::cout << a.Get<int>(10) << std::endl;
std::cout << a.Get<double>(10) << std::endl;
// Does not work. Produces compiler error.
// std::cout << a.Get<float>(10) << std::endl;
}
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
return 10*in;
}
}
Output:
20
100
Update
Here'a multiple file version:
MyClass.h:
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct Implemented;
template<typename T> struct API
{
static T Get(T const&);
};
API_TYPE(int);
API_TYPE(double);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
MyClass.cc:
#include "MyClass.h"
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
return 10*in;
}
}
main.cc:
#include <iostream>
#include "MyClass.h"
int main()
{
MyClass a;
std::cout << a.Get<int>(10) << std::endl;
std::cout << a.Get<double>(10) << std::endl;
// Does not work.
// std::cout << a.Get<float>(10) << std::endl;
}
It also builds successfully and produces the same result.
I am trying to create a concept for use with boost::any. This concept should say that
a class has ha member function with signatur void templateFunction(T t). I have gotten this to compile and working fine, but only for one type at a time. Is what I am trying to do impossible?
#include <iostream>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
class Foo
{
public:
template <class T>
void templateFunction(T t)
{
cout << t << endl;
}
};
template<class C, class T>
struct has_template_function
{
static void apply(C& cont, const T& arg) { cont.templateFunction(arg); }
};
namespace boost
{
namespace type_erasure
{
template<class C, class T, class Base>
struct concept_interface<has_template_function<C, T>, Base, C> : Base
{
void templateFunction(typename as_param<Base, const T&>::type arg)
{ call(has_template_function<C, T>(), *this, arg); }
};
}
}
int main()
{
any<has_template_function<_self, int>, _self&> c = Foo();
c.templateFunction(5);
//Compile error: cannot convert parameter 1 from 'const char [6]' to 'const int &'
//c.templateFunction("Hello");
return 0;
}
This is kind of possible by overloading, and documented in the official Boost.TypeErasure documentation.
The caveat is, as said in the comments:
You can't type-erase templates and keep their polymorphic nature
Therefore, you will have to specify the overloads explicitly in the requirements for your boost::typeerasure::any type.
You need to modify your concept interface as described in the docs, and add a string overload to the requirements section.
Your example, modified to handle overloads:
#include <iostream>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
#include <string>
#include <utility>
using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
struct FooStruct
{
template <class T>
void templateFunction(T t)
{
cout << t << endl;
}
};
template<class T, class U>
struct has_template_function
{
static void apply(T& t, const U& u) { t.templateFunction(u); }
};
namespace boost {
namespace type_erasure {
template<class T, class U, class Base, class Enable>
struct concept_interface< ::has_template_function<T, U>, Base, T, Enable> : Base
{
typedef void _fun_defined;
void templateFunction(typename as_param<Base, const U&>::type arg)
{
call(::has_template_function<T, U>(), *this, arg);
}
};
template<class T, class U, class Base>
struct concept_interface< ::has_template_function<T, U>, Base, T, typename Base::_fun_defined> : Base
{
using Base::templateFunction;
void templateFunction(typename as_param<Base, const U&>::type arg)
{
call(::has_template_function<T, U>(), *this, arg);
}
};
}
}
ostream& operator<<(ostream& os, const std::pair<int, string>& pair) {
os << "(" << pair.first << ", " << pair.second << ")";
return os;
}
int main()
{
any<
mpl::vector
<
has_template_function<_self, int>,
has_template_function<_self, std::string>,
has_template_function<_self, std::pair<int,std::string>>
>
, _self&> c = FooStruct();
c.templateFunction(5);
c.templateFunction("Hello");
c.templateFunction(std::make_pair(5, "Hello"));
return 0;
}