C++11 providing empty non-member function when it is missing - c++

In my serialization system, I can provide non-member functions that implement how to serialize given types:
// struct foo
struct foo {
int bar;
};
// serialize foo
template <class stream> void serialize(stream& s, foo& f) {
stream.serialize(f.bar);
}
If I wanted to provide an empty serialize implementation when a non-member function serialize does not exist for a given type, how can I achieve that using C++11?
I tried this
template <class stream, class type> void serialize(stream&, type&) {}
// struct foo
struct foo {
int bar;
};
// serialize foo
template <class stream> void serialize(stream& s, foo& f) {
stream.serialize(f.bar);
}
// ...later in source file:
foo f;
stream s;
serialize(s, f);
but it always calls the empty method somehow.

Add a non-member function template.
template <typename stream, typename T> void serialize(stream& s, T& t) {}
Here's a demonstrative program:
#include <iostream>
template <typename stream, typename type> void serialize(stream&, type&)
{
std::cout << "Came to 1\n";
}
struct stream
{
void serialize(int ) {}
};
// struct foo
struct foo {
int bar;
};
// serialize foo
template <class stream> void serialize(stream& s, foo& f) {
std::cout << "Came to 2\n";
s.serialize(f.bar);
}
struct bar {
};
int main()
{
// ...later in source file:
foo f;
stream s;
serialize(s, f);
bar b;
serialize(s, b);
}
and its output under cygwin/g++ 6.4.0:
Came to 2
Came to 1
It works at ideone.com too.

Related

Check for function existance on other type using C++ concepts

Does anybody know how to make a C++ concept T such that the function g is only defined for arguments t with type T if there exist an overload of f in B that accepts an argument t?
struct A1 {};
struct A2 {};
struct B {
void f(A1 a1) {}
};
void g(T t) {
B b;
b.f(t);
}
As an example, I want to define a to_string for everything that std::stringstream accepts, and define something like
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
All examples on concepts deal with the easier case of requiring the existance of a function on a type, while in this case we want to check existance of a function on another type.
If you want to check if the type is streamable or not, you can have something like:
#include <iostream>
#include <concepts>
#include <sstream>
template <typename T>
concept Streamable = requires (T x, std::ostream &os) { os << x; };
struct Foo {};
struct Bar {};
std::ostream& operator<<(std::ostream& os, Foo const& obj) {
// write obj to stream
return os;
}
template <Streamable T>
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
int main() {
Foo f;
Bar b;
to_string(f);
to_string(b); // error
return 0;
}
Demo
You can use two different type placeholders in a single concept, to require both the existence of a member function for an instance of one of the type placeholders, as well as the argument to said member function to match the type of another placeholder. E.g.:
#include <iostream>
template<typename T, typename U>
concept HasMemFnConstFoo = requires(const T t, const U u) {
t.foo(u);
};
template<typename U>
struct Bar {
template <typename T>
static void bar(const T& t)
{
if constexpr (HasMemFnConstFoo<T, U>) { t.foo(U{}); }
else { std::cout << "foo() not defined\n"; }
}
};
struct A1 {};
struct A2 {};
struct B1 {
void foo(const A1&) const { std::cout << "B1::foo()\n"; }
};
struct B2 {
void foo(const A1&) { std::cout << "B2::foo()\n"; }
};
struct B3 {
void foo(A1&) const { std::cout << "B3::foo()\n"; }
};
int main() {
Bar<A1>::bar(B1{}); // B1::foo()
Bar<A2>::bar(B1{}); // foo() not defined
Bar<A1>::bar(B2{}); // foo() not defined [note: method constness]
Bar<A2>::bar(B2{}); // foo() not defined
Bar<A1>::bar(B3{}); // foo() not defined [note: argument constness]
Bar<A2>::bar(B3{}); // foo() not defined
}

Friend explicit specialization of function template and ADL

Why in the following the partial specialization is not selected by ADL?
template<class T>
void func1(T&){ // selected
...
}
namespace first{
template<class R>
struct foo{
friend void func1<>(foo<R>&){ // expected
cout << "foo.func1" <<endl;
}
};
}
foo<int> f;
func1(f);
Template parameters are unrelated with friend declarations. You'll need to carry them disambiguated in thefriend declaration:
template<class R>
struct foo{
template<typename U>
friend void func1<U>(foo<U>&){
cout << "foo.func1" <<endl; // cat();
}
};
Also for your case you should decide, if you want to put the friend definition inlined as above, or just provide a declaration:
template<class R>
struct foo{
template<typename U>
friend void ::func1<U>(foo<U>&);
};
The latter should match the friend template function in the global namespace explicitly, and specialization can be made as necessary:
template<>
void func1(int&){
// ...
}
template<>
void func1(std::string&){
// ...
}
// a.s.o.
You don't need to provide an specialization of func1. Just provide an overload:
namespace first {
template <class R>
struct foo {
friend void func1(foo& ){
std::cout << "foo.func1" << std::endl;
}
};
}
int i;
first::foo<int> f;
func(i); // calls ::func<int>
func1(f); // calls first::func1(first::foo<int>& );
Otherwise, you can friend a specizliation, but you can't define a specialization in the class body:
template <class R>
struct foo {
friend void func1<>(foo& ); // friends ::func1<foo<R> >
};

Invalid use of incomplete type (class method specialization)

First, I've read over many other questions and couldn't find the solution. So before marking it a duplicate, please make sure duplicate answers the question.
I'm trying to specialize F::operator() for a class C2; however, C2 has a template parameter and I want F::operator() to behave the same for all C2's.
Compiler error:
error: invalid use of incomplete type ‘struct F<C2<T> >’
void F<C2<T>>::operator()()
Also, instead of Handle& h, I tried Handle* h and received the same error.
#include<iostream>
struct C1
{
void foo()
{
std::cout << "C1 called" << std::endl;
}
};
template<typename T>
struct C2
{
void bar();
};
template<>
void C2<int>::bar()
{
std::cout << "C2<int> called" << std::endl;
}
template<typename Handle>
struct F
{
F(Handle& h_) : h(h_) {}
void operator()();
Handle& h;
};
template<>
void F<C1>::operator()()
{
h.foo();
}
template<typename T>
void F<C2<T>>::operator()()
{
h.bar();
}
int main()
{
C1 c1;
F<C1> f_c1 (c1);
f_c1();
C2<int> c2;
F<C2<int>> f_c2 (c2);
f_c2();
}
There's no such thing like a partial specialization of a member function. You'd need to first partial-specialize the entire class:
template <typename T>
struct F<C2<T>>
{
void operator()();
};
template <typename T>
void F<C2<T>>::operator()() {}
Since this is a heavy-weight solution, alternatively, you can exploit tag-dispatching:
template <typename T> struct tag {};
template <typename Handle>
struct F
{
F(Handle& h_) : h(h_) {}
void operator()()
{
call(tag<Handle>{});
}
private:
void call(tag<C1>)
{
h.foo();
}
template <typename T>
void call(tag<C2<T>>)
{
h.bar();
}
Handle& h;
};
DEMO

How to use functor as a member in class template?

I was trying to use a functor as a std::function object inside a class template. Below is what I have done so far.
//! the functor class template
template<typename T>
struct func
{
void operator ()(T t)
{
std::cout << t << "\n";
}
};
//! the class template that holds a std::function object as a member
template<typename T>
struct Foo
{
std::function<void(T)> bar = func<T>();
};
int main()
{
Foo<int> foo;
return 0;
}
It was complained that
error: conversion from 'func<int>' to non-scalar type 'std::function<void(int)>' requested
struct Foo
^
Is it possible to do so? How to fix it?
You can either make it static and initialize it outside class-scope, or initialize it in the constructor. Tested on GCC 4.7.2.
template<typename T>
struct Foo
{
static std::function<void(T)> bar;
};
template <typename T>
std::function<void(T)> Foo<T>::bar = func<T>();
EDIT
In C++11, you can also use brace-initialization:
std::function<void(T)> bar { func<T>() };
Different ways to use std::function in a non-static data member initializer
#include <functional>
#include <iostream>
#define ENABLE_CONVERSION 1
template<typename T>
struct func
{
void operator ()(T t)
{
std::cout << "Function: " << t << "\n";
}
#if ENABLE_CONVERSION
// FIX: error: conversion from ‘func<int>’ to non-scalar type
// ‘std::function<void(int)>’ requested
operator std::function<void(T)> () { return std::function<void(T)>(*this); }
#endif
};
template<typename T>
struct Foo
{
std::function<void(T)> bar0 = std::function<void(T)>(func<T>());
std::function<void(T)> bar1{func<T>()};
// Error without ENABLE_CONVERSION
std::function<void(T)> bar2 = func<T>();
static std::function<void(T)> bar3;
void operator() () {
bar0(0);
bar1(1);
bar2(2);
bar3(3);
}
};
template<typename T>
std::function<void(T)> Foo<T>::bar3 = func<T>();
template<typename T>
void goo() {
// This compiles without ENABLE_CONVERSION:
// What is the difference to non-static data member initializers ?
std::function<void(T)> g = func<T>();
g(4);
}
int main()
{
Foo<int> foo;
foo();
goo<int>();
return 0;
}
Additional question
I tried to find differences between variable brace-or-equal-initializer
and the non-static data member brace-or-equal-initializer. I found nothing.
What is the difference between
std::function<void(T)> bar2 = func<T>();
and
std::function<void(T)> g = func<T>();
when ENABLE_CONVERSION is zero?
In your case std::function is optional, use direct functor itself.
//! the functor class template
template<typename T>
struct func
{
void operator ()(T t)
{
std::cout << t << "\n";
}
};
//! the class template that holds a std::function object as a member
template<typename T>
struct Foo
{
//std::function<void(T)> bar = func<T>(); <-- **removed, because std::function isn't cheap as func<T>**.
func<T> bar;//default initialized itself.
};
int main()
{
Foo<int> foo;
foo.bar(24);//prints 24.
return 0;
}
EDIT:
In common case, move template from struct declration to the operator, i.e. as:
struct func
{
template< typename T >
void operator()(T t ) const { std::cout << t << '\n'; }
};
struct Foo
{
func m_func;
};
int main(){
Foo f;
f.m_func(24); // prints 24
f.m_func("hello world"); // prints "hello world"
f.m_func(3.143); // prints 3.143
// and etc.,
};
in c++14, std::less<>, std::greater<> and more other functors template keyword moved to the operator declaration, instead of struct declaration, it's help more generic comparation.
Edit2: You may use following technicus:
struct func{
template< typename T > void operator()(T t) const{ std::cout << t << '\n';}
};
template< typename T, typename Functor> // Functor as template
struct Foo
{
Functor m_Functor; //--> functor member
T m_Data; // or something else.
};
// create `makeFoo` for auto deduced functor type.
template< typename T, typename Functor>
Foo<T,Functor> makeFoo(Functor f, T t ) { return {f,t}; }
int print(int i, int j){ std::cout << i+j << '\n' ;}
int main()
{
auto foo = makeFoo(24, func{} );
// use foo
auto foo2 = makeFoo("hello", std::bind(print, 2, _1) );
// use foo2
}

boost concept check operator() overload

template <typename T, typename C>
class CSVWriter{
template <typename PrinterT>
void write(std::ostream& stream, const PrinterT& printer){
}
};
I want to check whether there exists at least two overloads PrinterT::operator()(T*) and PrinterT::operator()(C*)
PrinterT may or may not inherit from std::unary_function
What concept Checking Classes I need to use here ?
(I am not using C++11)
You can use something like that
#include <iostream>
#include <boost/concept/requires.hpp>
#include <boost/concept/usage.hpp>
template <class Type, class Param>
class has_operator_round_brackets_with_parameter
{
public:
BOOST_CONCEPT_USAGE(has_operator_round_brackets_with_parameter)
{
_t(_p);
}
private:
Type _t;
Param _p;
};
struct X {};
struct Y {};
struct Test1
{
void operator() (X*) const { }
};
struct Test2: public Test1
{
void operator() (X*) const { }
void operator() (Y*) const { }
};
template <class T, class C>
struct CSVWriter
{
template <class PrinterT>
BOOST_CONCEPT_REQUIRES(
((has_operator_round_brackets_with_parameter<PrinterT, T*>))
((has_operator_round_brackets_with_parameter<PrinterT, C*>)),
(void)) write(std::ostream& stream, const PrinterT& printer)
{
}
};
int main()
{
CSVWriter<X, Y> w;
// w.write<Test1>(std::cout, Test1()); // FAIL
w.write<Test2>(std::cout, Test2()); // OK
return 0;
}