Concatenate compile-time strings in a template at compile time?

前端 未结 3 1693
猫巷女王i
猫巷女王i 2020-12-08 12:47

Currently I have:

template  struct typename_struct {
    static char const* name() { 
        return (std::string(typename_struc         


        
相关标签:
3条回答
  • 2020-12-08 13:03

    You could use something like this. Everything happens at compile time. Specialize base_typename_struct to define your primitive types.

    template <const char* str, int len, char... suffix>
    struct append {
      static constexpr const char* value() {
        return append<str, len-1, str[len-1], suffix...>::value();
      }
    };
    
    template <const char* str, char... suffix>
    struct append<str, 0, suffix...> {
      static const char value_str[];
      static constexpr const char* value() {
        return value_str;
      }
    };
    
    template <const char* str, char... suffix>
    const char append<str, 0, suffix...>::value_str[] = { suffix..., 0 };
    
    
    template <typename T>
    struct base_typename_struct;
    
    template <>
    struct base_typename_struct<int> {
      static constexpr const char name[] = "int";    
    };
    
    
    template <typename T, char... suffix>
    struct typename_struct {
      typedef base_typename_struct<T> base;
      static const char* name() {
        return append<base::name, sizeof(base::name)-1, suffix...>::value();
      }
    };
    
    template <typename T, char... suffix>
    struct typename_struct<T*, suffix...>:
      public typename_struct<T, '*', suffix...> {
    };
    
    
    int main() {
      cout << typename_struct<int****>::name() << endl;
    }
    
    0 讨论(0)
  • 2020-12-08 13:04

    I'm not sure of what you're searching for but I believe you're interested in a combination of typeid and name-demangling (which compiler are you using?)

    In gcc it would be something like

    #include<iostream>
    #include <string>
    #include <typeinfo>
    #include <cstdlib>
    #include <memory>
    #include <cxxabi.h>
    using namespace std;
    
    std::string demangle(const char* name) {
        int status = -4; // some arbitrary value to eliminate the compiler warning
    
        // enable c++11 by passing the flag -std=c++11 to g++
        std::unique_ptr<char, void(*)(void*)> res {
            abi::__cxa_demangle(name, NULL, NULL, &status),
            std::free
        };
        return (status==0) ? res.get() : name ;
    }
    
    template <typename T> struct typename_struct {
      static std::string name() {
        std::string typeName = typeid(T).name();
        return demangle(typeName.c_str());
      }
    };
    
    int main(){
    
      cout << typename_struct<int****>::name(); // Prints "int****"
    
      return 0;
    }
    

    http://ideone.com/nLsFF0

    Sources: https://stackoverflow.com/a/4541470/1938163

    As for your question: those aren't constexpr constructs, thus the evaluation happens at runtime although the templated parameters and code are instantiated at compile-time.

    Using templates doesn't mean every instruction contained in there will be executed and resolved at "compile-time".

    I believe you can't achieve this whole bunch of stuff at compile-time since there are de-mangling functions (ABI-specific) involved. If I interpreted your question wrong please let me know.

    0 讨论(0)
  • 2020-12-08 13:17

    Alternative way without using recursive templates (but requires C++14):

    #include <utility>
    template<int...I> using is      = std::integer_sequence<int,I...>;
    template<int N>   using make_is = std::make_integer_sequence<int,N>;
    
    constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }
    
    template<const char*, typename, const char*, typename>
    struct concat_impl;
    
    template<const char* S1, int... I1, const char* S2, int... I2>
    struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
        static constexpr const char value[]
        {
            S1[I1]..., S2[I2]..., 0
        };
    };
    
    template<const char* S1, const char* S2>
    constexpr auto concat {
        concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value
    };
    

    Example:

    constexpr const char a[] = "int";
    constexpr const char c[] = "**";
    
    #include <iostream>
    int main()
    {
        std::cout << concat<a,b> << '\n';
    }
    

    append characters to string can also be implemented like this, by replacing the second const char* parameter with char....

    0 讨论(0)
提交回复
热议问题