Where do regular templates and meta templates end?

Jörg’s answer to this question nicely delineates between “normal” templates (which this question may possibly fall into error as generics) that work with data and meta templates that work with the program. Jörg then wisely mentions that programs are data, so it really is all the same. However, meta templates are still another beast. Where do regular templates and meta templates end?

The best test I can come up with is if the template arguments are exclusive classor typename, the template is “normal” and meta different. Is this test correct?

+6
source share
4 answers

Trying to differentiate and define terms

First, try to roughly define the terms. I start with a fairly reliable definition of "programming", and then reapply the "normal" meaning to it meta-:

programming

Programming leads to a program that converts some data.

int add(int value) { return value + 42; }

I just wrote code that will lead to a program that converts some data - an integer - to some other data.

patterns (metaprogramming)

- "" , . ++ "", .

template<typename T>
std::pair<T,T> two_of_them(T thing) {
  return std::make_pair(thing, thing);
}

, , ( ) .

(-?)

- "" , "" , . , ++ , . ( :)

// map :: ([T] -> T) -> (T -> T) -> ([T] -> T)
//         "List"       "Mapping"   result "type" (also a "List")
// --------------------------------------------------------
template<template<typename...> class List,
         template<typename> class Mapping>
struct map {
  template<typename... Elements>
  using type = List<typename Mapping<Elements>::type...>;
};

, .

, , "" -, " ", "". , "" ? , , (auto p = two_of_them(42);) ( "" ).

, , (, ), , .

. :

template<typename X>
struct foo {
  template<typename Y>
  using type = X;
};

foo - typename, "" ( foo::type... ), "" - , - , foo (, , , , ).

+1

:

, , , , , , / .

, .. , , , , cpp, .

()

. ( , , , ):

template<typename T>
T add(const T& lhs, const T& rhs) {
    return(lhs + rhs);
}

template<>
std::string add<std::string>(
                const std::string& lhs,
                const std::string& rhs) {
     return (lhs.append(rhs));
}

int main() {
    double      result = add(1.0, 2.0); // 3.0
    std::string s      = add("This is ", " the template specialization..."); 
}

double, , . , , : .

:

#include <iostream>
#include <string>
#include <type_traits>

class INPCWithVoice {
    void doSpeak() { ; }
};

class DefaultNPCWithVoice 
    : public INPCWithVoice {
    public:
        inline std::string doSpeak() {
            return "I'm so default, it hurts... But at least I can speak...";
        }
}; 

class SpecialSnowflake
    : public INPCWithVoice {
    public:
        inline std::string doSpeak() {
            return "WEEEEEEEEEEEH~";   
        }
};

class DefaultNPCWithoutVoice {
    public:
         inline std::string doSpeak() {
            return "[...]";
        }
};

template <typename TNPC>
static inline void speak(
    typename std::enable_if<std::is_base_of<INPCWithVoice, TNPC>::value, TNPC>::type& npc) 
{
    std::cout << npc.doSpeak() << std::endl;
};

int main()
{
    DefaultNPCWithVoice    npc0 = DefaultNPCWithVoice();
    SpecialSnowflake       npc1 = SpecialSnowflake();
    DefaultNPCWithoutVoice npc2 = DefaultNPCWithoutVoice();

    speak<DefaultNPCWithVoice>(npc0);
    speak<SpecialSnowflake>(npc1);
    // speak<DefaultNPCWithoutVoice>(npc2); // Won't compile, since DefaultNPCWithoutVoice does not derive from INPCWithVoice
}

- ( ...). , , "" , TNPC, , , INPCWithVoice.

, , , , , . SFINAE : http://eli.thegreenplace.net/2014/sfinae-and-enable_if/

, , /

: https://akrzemi1.wordpress.com/2012/03/19/meta-functions-in-c11/

, , - , - .

:

#include <iostream>
#include <string>
#include <type_traits>

template <intmax_t N>
static unsigned int fibonacci() {
    return fibonacci<N - 1>() + fibonacci<N - 2>();     
}

template <>
unsigned int fibonacci<1>() {
    return 1;   
}

template <>
unsigned int fibonacci<2>() {
    return fibonacci<1>();    
}

template <intmax_t MAX>
    static void Loop() {
    std::cout << "Fibonacci at " << MAX << ": " << fibonacci<MAX>() << std::endl;
    Loop<MAX - 1>();
}

template <>
void Loop<0>() {
    std::cout << "End" << std::endl;    
}

int main()
{
    Loop<10>();
}

N. , 10 0!

, .

, : !!!

, !!!

, , - - stackoverflow, .

+5

.com

-

  1. , , , , : ; .

  2. , , : - .

, ++. , , .

. () .

, , , , , . , .

:

std:: aligned_storage;

template<std::size_t Len, std::size_t Align /* default alignment not implemented */>
struct aligned_storage {
    typedef struct {
        alignas(Align) unsigned char data[Len];
    } type;
};

, std::aligned_storage . ,

template<typename T>
using storage_of = std::aligned_storage<sizeof(T), alignof(T)>::type;

, T, , , . .

std::aligned_storage , . , . , , , type::data.

:

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> class priority_queue { /*Implementation defined implementation*/ };

:

, , ?

, . std::priority_queue - , . :

template<typename C>
using PriorityQueue = std::priority_queue<C>;

, . , , .

std::priority_queue, , . , , . .

, , PriotityQueue. , , , Boost.Heap Qt , . , - , , .

(Meta-)

, , storage_of typename, -. , , , , Turing-complete. - , , , (.. )

using Z = void;
template<typename> struct Zermelo;
template<typename N> using Successor = Zermelo<N>;

, . , , , .

, . .

, ( template<class Iterator> struct is_pointer_like;

template<class It> generateSomeData(It outputIterator) {
    if constexpr(is_pointer_like<outputIterator>::value) {
        generateFastIntoBuffer(static_cast<typename It::pointer> (std::addressof(*outputIterator));
    } else {
        generateOneByOne(outputIterator);
    }
}

, - .

+1

?

, , , , - .

, :

bool greater(int a, int b)
{
   return (a > b);
}

, ( ).

( )

template <typename T>
bool greater(T a, T b)
{
   return (a > b);
}

, , . , , C.

// Generic implementation
template <typename T>
struct greater_helper
{
   bool operator(T a, T b) const
   {
     return (a > b);
   }
};

template <typename T>
bool greater(T a, T b)
{
   return greater_helper<T>().(a > b);
}

// Specialization for char const*
template <>
struct greater_helper<char const*>
{
   bool operator(char const* a, char const* b) const
   {
     return (strcmp(a, b) > 0);
   }
};

, :

If a T - char const*, .
T .

Now you cross the threshold of standard patterns for metaprogramming patterns. You introduced the concept of if-else, forked using templates.

0
source

Source: https://habr.com/ru/post/1016400/


All Articles