English 中文(简体)
C++ 编篡时间分校
原标题:C++ compile-time substring

I have very big code-base, which uses __FILE__ extensively for logging. However, it includes full path, which is (1) not needed, (2) might case security violations.

我试图撰写时间分指示的表述。 Ended with this Solutions

static constexpr cstr PastLastSlash(cstr str, cstr last_slash)
{
    return *str ==    ? last_slash : *str ==  /  ? PastLastSlash(str + 1, str + 1) : PastLastSlash(str + 1, last_slash);
}

static constexpr cstr PastLastSlash(cstr str)
{
    return PastLastSlash(str, str);
}

// usage
PastLastSlash(__FILE__);

这一工作良好,即我检查的组装法典,在汇编时间时,只有双手名称。

However, this notation is too verbose. I would like to use macro for this, but failed. Proposed example from the link above

#define __SHORT_FILE__ ({constexpr cstr sf__ {past_last_slash(__FILE__)}; sf__;})

MSVC汇编者(使用MSVC2017)。 是否有其他方法使用++17?

http://godbolt.org/z/tAU4j7

<>UPD2:认为,在利用职能汇编时间方面可以做三番工作,但全方位将出现在双位。

最佳回答

想法是创造一系列的特征,但只需要汇编时间特征。 通过单体模版生成数据阵列,并配有成套的果园汇编器,以生成数据而不与经过的字面直接相关。 这样,汇编者不能用字面说明投入,特别是在这种描述很长的情况下。

Godbolt with Corng: https://godbolt.org/z/WdKNjB

Godbolt with msvc: https://godbolt.org/z/auMEIH

唯一的问题是模板深度汇编环境。

第一,我们界定了用于储存指数序列的斜体模:

template <int... I>
struct Seq {};

Pushing int to Seq:

template <int V, typename T>
struct Push;

template <int V, int... I>
struct Push<V, Seq<I...>>
{
    using type = Seq<V, I...>;
};

建立顺序:

template <int From, int To>
struct MakeSeqImpl;

template <int To>
struct MakeSeqImpl<To, To>
{
    using type = Seq<To>;
};

template <int From, int To>
using MakeSeq = typename MakeSeqImpl<From, To>::type;

template <int From, int To>
struct MakeSeqImpl : Push<From, MakeSeq<From + 1, To>> {};

现在我们可以确定时间序列,即<代码>。 Mark Seq<3,7>=Seq<3,4,5,6,7>。 然而,我们需要在阵列中储存某些特性,但需要汇编时间代表,即具有特性的单体模板参数:

template<char... CHARS>
struct Chars {
    static constexpr const char value[] = {CHARS...};
};
template<char... CHARS>
constexpr const char Chars<CHARS...>::value[];

接下来,我们要把选定的特性引向<代码>。 Chars 类型:

template<typename WRAPPER, typename IDXS>
struct LiteralToVariadicCharsImpl;

template<typename WRAPPER, int... IDXS>
struct LiteralToVariadicCharsImpl<WRAPPER, Seq<IDXS...> > {
    using type = Chars<WRAPPER::get()[IDXS]...>;
};

template<typename WRAPPER, typename SEQ>
struct LiteralToVariadicChars {
    using type = typename LiteralToVariadicCharsImpl<WRAPPER, SEQ> :: type;
};

几乎做了。 失踪人员部分是最后lash。 我们可以使用经修改的《守则》文本,但此时此刻,《守则》不再提及:

static constexpr int PastLastOffset(int last_offset, int cur, const char * const str)
{
    if (*str ==   ) return last_offset;
    if (*str ==  / ) return PastLastOffset(cur + 1, cur + 1, str + 1);
    return PastLastOffset(last_offset, cur + 1, str + 1);
}

• 最后用于缩小面积:

constexpr int StrLen(const char * str) {
    if (*str ==   ) return 0;
    return StrLen(str + 1) + 1;
}

1. 结合一切方法,界定:

#define COMPILE_TIME_PAST_LAST_SLASH(STR)                                   
    [](){                                                                   
        struct Wrapper {                                                    
            constexpr static const char * get() { return STR; }             
        };                                                                  
        using Seq = MakeSeq<PastLastOffset(0, 0, Wrapper::get()), StrLen(Wrapper::get())>; 
        return LiteralToVariadicChars<Wrapper, Seq>::type::value; 
    }()

Lambda的功能是在使用这一宏观方法时有冰、价值类似的感觉。 它还为界定<代码>Wrapper结构创造了条件。 形成这种结构时用宏观字面加插,导致在字面上被限制为类型时的情况。

很抱歉,我不会在生产中使用这种法典。 它是杀人的汇编者。

在安全原因和记忆使用的情况下,我建议使用cker,使用短路建造。

问题回答

您可使用:

constexpr auto filename(std::string_view path)
{ 
    return path.substr(path.find_last_of( / ) + 1);
}

使用:

static_assert(filename("/home/user/src/project/src/file.cpp") == "file.cpp");
static_assert(filename("./file.cpp") == "file.cpp");
static_assert(filename("file.cpp") == "file.cpp");

compile(godbolt.org)。

视窗:

constexpr auto filename(std::wstring_view path)
{ 
    return path.substr(path.find_last_of(L \ ) + 1);
}

有了C++17,你可以做以下工作():

#include <cstdio>
#include <array>

namespace details {
template <const char *S, size_t Start = 0, char... C>
struct PastLastSlash {
    constexpr auto operator()() {
        if constexpr (S[Start] ==   ) {
            return std::array{C...,   };
        } else if constexpr (S[Start] ==  / ) {
            return PastLastSlash<S, Start + 1>()();
        } else {
            return PastLastSlash<S, Start + 1, C..., (S)[Start]>()();
        }
    }
};
}

template <const char *S>
struct PastLastSlash {
    static constexpr auto a = details::PastLastSlash<S>()();
    static constexpr const char * value{a.data()};
};


int main() {
    static constexpr char f[] = __FILE__;
    puts(PastLastSlash<f>::value);
    return 0;
}

参照C++14,由于经验比较有限(:https://godbolt.org/z/bzGec5GMv):

#include <cstdio>
#include <array>

namespace details {
// Generic form: just add the character to the list
template <const char *S, char ch, size_t Start, char... C>
struct PastLastSlash {
    constexpr auto operator()() {
        return PastLastSlash<S, S[Start], Start + 1, C..., ch>()();
    }
};

// Found a  / , reset the character list
template <const char *S, size_t Start, char... C>
struct PastLastSlash<S,  / , Start, C...> {
    constexpr auto operator()() {
        return PastLastSlash<S, S[Start], Start + 1>()();
    }
};

// Found the null-terminator, ends the search
template <const char *S, size_t Start, char... C>
struct PastLastSlash<S,   , Start, C...> {
    constexpr auto operator()() {
        return std::array<char, sizeof...(C)+1>{C...,   };
    }
};
}

template <const char *S>
struct PastLastSlash {
    const char * operator()() {
        static auto a = details::PastLastSlash<S, S[0], 0>()();
        return a.data();
    }
};


static constexpr char f[] = __FILE__;
int main() {
    puts(PastLastSlash<f>{}());
    return 0;
}

With C++20 (https://godbolt.org/z/PKEhxdrEz):
(Note: it s not clear if it s safe in MSVC. Godbolt shows that the full string is encoded in the name of the template, but when I search the binary, I do not find it)

#include <cstdio>
#include <array>
#include <string>

namespace details {
template<size_t N>
struct PastLastSlash {
    constexpr PastLastSlash(const char (&s)[N]) {
        std::string str{s};
        size_t pos = str.rfind( / );
        if (pos == std::string::npos) {
            pos = 0;
        } else {
            ++pos;
        }
        size_t len = str.length() - pos + 1;
        std::copy(s+pos, s+pos+len, value.data());      
    }
    constexpr size_t len() const {
        std::string str{value.data()};
        return str.length()+1;
    }
    std::array<char, N> value{};
};
}

template <details::PastLastSlash S>
struct PastLastSlash {
    static constexpr std::array<char, S.len()> copy() {
        std::array<char, S.len()> arr;
        std::copy(S.value.data(), S.value.data()+S.len(), arr.data());      
        return arr;
    }
    static constexpr std::array<char, S.len()> arr{copy()};
    static constexpr const char *value = arr.data();
};


int main() {
    puts(PastLastSlash<__FILE__>::value);
    return 0;
}




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签