Template return struct fields

Hi, is it possible to define as template the following get functions. Thanks.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Config  {
public:
        enum { NO_ID = 999 };
	struct ValueType {
		bool a;
		size_t b;
		std::time_t c;
	};

	bool get_a(int id = NO_ID) {
		bool result = _a;
		if (id != NO_ID) {
			try {
				ValueType val = getFromDB(id);
				result = val.a;
			} catch () {...}
		}
		return result;
	}
	size_t get_b(int id = NO_ID) {
		size_t result = _b;
		if (id != NO_ID) {
			try {
				ValueType val = getFromDB(id);
				result = val.b;
			} catch () {...}
		}
		return result;
	}
	std::time_t get_c(int id = NO_ID) {
		std::time_t result(nullptr);
		if (id != NO_ID) {
			try {
				ValueType val = getFromDB(id);
				result = val.c;
			} catch () { ... }
		}
		return result;
	}

private:
	bool _a;
	size_t _b;
	std::time_t _c;
};

Hi, is it possible to define as template the following get functions. Thanks.
Depends on what you're trying to accomplish.
Thanks for reply. I would like to avoid code repetition inside the functions get_a, get_b, get_c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <ctime>
#include <string>

struct config
{
    enum { NO_ID = 999 };

    struct value_type
    {
        bool a ; operator bool() const { return a ; }
        std::size_t b ; operator std::size_t() const { return b ; }
        std::time_t c ; operator  std::time_t() const { return c ; }
        std::string d ; operator  std::string() const { return d ; }
    };

    value_type getFromDB( int /* id */ ) { /* ... */ throw "something" ; }

    value_type do_getFromDB( int id ) const
    {
        try {  /* ... */ return do_getFromDB(id) ; }
        catch(...) { return { a, b, c, d } ; }
    }

    template < typename T > T get( int id = NO_ID )
    { return id != NO_ID ? getFromDB(id) : value_type{ a, b, c, d } ; }

    private:
        bool a = false ;
        std::size_t b = 492 ;
        std::time_t c = std::time(nullptr) ;
        std::string d = "hello";
};

int main()
{
    config c ;
    std::cout << std::boolalpha << c.get<bool>() << '\n'
              << c.get<std::size_t>() << '\n'
              << c.get<std::time_t>() << '\n'
              << c.get<std::string>() << '\n' ;
}

http://coliru.stacked-crooked.com/a/b096bc56976efbec
Thanks you very much! The only issue is that value_type may have different fields with the same type:
1
2
3
4
5
6
7
8
9
struct value_type
    {
        bool a1 ; 
        bool a2;
        bool a3;
        std::size_t b ;
        std::time_t c ;
        std::string d ;
    };
Found the following solution with struct every field and get template specialization. If there are simpler proposals - welcome. Thanks again!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <typeinfo>

using namespace std;

class Config  {
public:

  enum { NO_ID = 999 };

  struct aType { bool a; };
  struct bType { size_t b; };
  struct cType { time_t c; };
  struct ValueType {
    aType aField;
    bType bField;
    cType cField;
  };
  Config( bool a, size_t b, time_t c) {
    _a.a = a;
    _b.b = b;
    _c.c = c;
  }
  template <typename T>
  T getField(ValueType val) { throw "Unknown type"; }

  template <typename T>
  T getDefaultField() { throw "Unknown type"; }

  //  template <typename T>
  //void fun1(T val) { cout << "-D- Fun1 type=" << typeid(val).name() << endl; }

  template <typename T>
  T get(int id = NO_ID ) {
    T result = getDefaultField<T>();
    if (id != NO_ID) {
      ValueType val = do_getFromDB(id);
      result = getField<T>(val);
    }
    return result;
  }

  ValueType getFromDB( int /* id */ ) { /* ... */ throw "something" ; }
  
  ValueType do_getFromDB( int id ) 
  {
    try {  /* ... */ return getFromDB(id) ; }
    catch(...) { 
      cout << "-E- Cannot get from DB id=" << id << endl;
      ValueType defaultVal = { _a, _b, _c};
      return defaultVal;
    }
  }

private:
  aType _a;
  bType _b;
  cType _c;
};

// Explicit specialization of getField
template <>
Config::aType Config::getField(ValueType val) { return val.aField; }

template <>
Config::bType Config::getField(ValueType val) { return val.bField; }

template <>
Config::cType Config::getField(ValueType val) { return val.cField; }

// Explicit specialization of getDefaultField
template <>
Config::aType Config::getDefaultField() { return _a; }

template <>
Config::bType Config::getDefaultField() { return _b; }

template <>
Config::cType Config::getDefaultField() { return _c; }

int main() {
   time_t tm(333);
   Config conf(true, 111, tm);
   Config::aType a2 = { false };
   Config::bType b2 = { 222 };
   Config::cType c2 = { tm };

   cout << "-D- Call conf.get<aType>(101)\n";	
   Config::aType aResult = conf.get<Config::aType>(101);  
   cout << "-D- aResult=" << std::boolalpha << aResult.a << endl;

   cout << "-D- Call conf.get<bType>(102)\n";	
   Config::bType bResult = conf.get<Config::bType>(102);  
   cout << "-D- bResult=" << bResult.b << endl;

   cout << "-D- Call conf.get<cType>(101)\n";	
   Config::cType cResult = conf.get<Config::cType>(101);  
   cout << "-D- cResult=" << cResult.c << endl;
}

http://coliru.stacked-crooked.com/a/0950db19e879631b
Not simpler; but more malleable: name and (stringified) value pairs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <ctime>
#include <string>
#include <map>
#include <typeindex>
#include <stdexcept>
#include <sstream>

struct config
{
    enum { NO_ID = 999 };

    std::string getFromDB( int /* id */ ) const { throw std::domain_error( "no id" ) ; }

    template < typename T > void add_item( std::string name, T& value, int id = NO_ID )
    {
        const std::string str_value = stringify(value) ;
        if( id != NO_ID ) { /* try write/update DB with name/str_value*/ }
        std::type_index ti = typeid(value) ;
        name_value_map.emplace( name, std::make_pair( ti, str_value ) ) ;
    }

    template < typename T > T& get( std::string name, T& value, int id = NO_ID ) const
    {
        std::string str_value = look_up( name, typeid(value) ) ;

        if( id != NO_ID )
        {
            try { str_value = getFromDB(id) ; }
            catch( const std::exception& ) {}
        }

        std::istringstream stm(str_value) ;
        stm >> std::boolalpha >> value ;
        return value ;
    }

    private:
        std::map< std::string, std::pair< std::type_index, std::string > > name_value_map
        {
            { "a1", { typeid(bool), "true" } },
            { "a2", { typeid(bool), "false" } },
            { "a3", { typeid(bool), "true" } },
            { "size",  { typeid(std::size_t), std::to_string(999) } },
            { "when",  { typeid(std::time_t), std::to_string( std::time(nullptr) ) } },
            { "greeting",  { typeid(std::string), "hello" } }
        };

        template < typename T > std::string stringify( const T& v )
        {
            std::ostringstream stm ;
            stm << std::boolalpha << v ;
            return stm.str() ;
        }

        std::string look_up( std::string name, std::type_index ti ) const
        {
            const auto iter = name_value_map.find(name) ;

            if( iter == name_value_map.end() ) throw std::domain_error( "no name" ) ;
            else if( ti != iter->second.first ) throw std::domain_error( "bad type" ) ;

            return iter->second.second ;
        }
};

int main()
{
    config cfg ;

    bool b1, b2 ;
    std::size_t s ;
    std::time_t t ;
    std::string str ;
    std::cout << std::boolalpha << "a1: " << cfg.get( "a1", b1 ) << '\n'
              << "a2: " << cfg.get( "a2", b2 ) << '\n'
              << "size: " << cfg.get( "size", s ) << '\n'
              << "when: " << cfg.get( "when", t ) << '\n'
              << "greeting: " << cfg.get( "greeting", str ) << '\n' ;

    try { std::cout << "colour: " << cfg.get( "colour", b1 ) << '\n' ; }
    catch( const std::exception& e ) { std::cerr << "error: " << e.what() << '\n' ; }

    try { std::cout << "size: " << cfg.get( "size", b1 ) << '\n' ; }
    catch( const std::exception& e ) { std::cerr << "error: " << e.what() << '\n' ; }

    long clr = 778899 ;
    cfg.add_item( "colour", clr ) ;

    clr = 0 ;
    std::cout << "colour: " << cfg.get( "colour", clr ) << '\n' ;
}

http://coliru.stacked-crooked.com/a/188dc477debca5ee
Topic archived. No new replies allowed.