2

I want to make integral constant from char* and "kernel32.dll", but failed always. The following are my failed attempts, anyone can show me the correct usage?

error 1: cout << std::integral_constant<const char*, "kernel32.dll">::value << endl;
error 2: cout << std::integral_constant<char*, "kernel32.dll">::value << endl;
error 3: cout << std::integral_constant<char[], "kernel32.dll">::value << endl;
error 4: cout << cout << std::integral_constant<char*, static_cast<char*>("kernel32.dll")>::value << endl;

the above 4 statements have the same error info.:

Console.cpp(181): error C2762: 'std::integral_constant' : invalid expression as a template argument for '_Val'
1>          D:\Programfiles\Visual Studio 2013\VC\include\xtr1common(35) : see declaration of 'std::integral_constant'
1>Console.cpp(181): error C2955: 'std::integral_constant' : use of class template requires template argument list
1>          D:\Programfiles\Visual Studio 2013\VC\include\xtr1common(35) : see declaration of 'std::integral_constant'
1>Console.cpp(181): warning C4552: '<<' : operator has no effect; expected operator with side-effect

Update:

std::integral_constant<std::string, "abc">::value won't compile either.

end update

Here is my scenario, I make a simple demo to demonstrate my purpose:

#include <iostream>
#include <type_traits>

template< typename R, typename C, typename... Args>
class delegate
{
public:
    template<R(C::*F)(Args...), typename ... Ts>
    struct adapter
    {
        static R invoke_no_fwd(Args... args)
        {
            C t((Ts::value)...);
            return (t.*F)(args...);
        }
    };
};

class Class
{
public:
    Class(const char* psz) {
        std::cout << psz << std::endl;
    }
    void print(int v)
    {
        std::cout << "Class: " << v << std::endl;
    }
};

int main()
{
    typedef void(*function_t)(int);
    function_t ptrFunc = delegate<void, Class, int>::adapter<&Class::print, std::integral_constant<char*, "money"> >::invoke_no_fwd;
    auto type = delegate<void, Class, int>::adapter<&Class::print, std::integral_constant<int, 42>>::invoke_no_fwd;
    ptrFunc(-42); // 0
    type(0); // 42

    return 0;
}
milleniumbug
  • 15,379
  • 3
  • 47
  • 71
Triumphant
  • 948
  • 1
  • 11
  • 28

2 Answers2

5

The template parameter type in your code, currently instantiated with std::integral_constant<>, is used only to access ::value static member, so you can replace it with any other type defining value member, just like shown below:

#include <iostream>

template <typename T>
void print()
{
    std::cout << (T::value) << std::endl;
}

struct X
{
    static const char* value;
};

const char* X::value = "ABC";

int main()
{
    print<X>();
}

That is, just put X in place of std::integral_constant<>.

function_t ptrFunc
    = delegate<void, Class, int>
          ::adapter<&Class::print, X /*here!*/>
          ::invoke_no_fwd;

Live demo link.


UPDATE 1

If you want to specify the string's content inline, within template instantiation, the below code will do the trick:

template <char... Chars>
struct MyString
{
    static constexpr char value[] = { Chars..., '\0' };
};

template <char... Chars>
constexpr char MyString<Chars...>::value[];

// MyString<'A', 'B', 'C'>::value is same as const char[4] = { "ABC" };

function_t ptrFunc
    = delegate<void, Class, int>
          ::adapter<&Class::print, MyString<'A', 'B', 'C'>>
          ::invoke_no_fwd;

Another live demo link.


UPDATE 2

If you are tired of typing MyString<'k','e','r','n','e','l','3','2','.','d','l','l'> you can instead expand a raw string like "kernel32.dll" into comma-separated characters list compliant with MyString<char...> template, using below macro (that for simplicity is limited to 32-character-long strings):

#include <iostream>

#define STR_1(S,I) (I < sizeof(S) ? S[I] : '\0')
#define STR_2(S,I) STR_1(S,I), STR_1(S,I+1)
#define STR_4(S,I) STR_2(S,I), STR_2(S,I+2)
#define STR_8(S,I) STR_4(S,I), STR_4(S,I+4)
#define STR_16(S,I) STR_8(S,I), STR_8(S,I+8)
#define STR_32(S,I) STR_16(S,I), STR_16(S,I+16)
#define STR(S) STR_32(S,0)

template <char... Chars>
struct MyString
{
    static constexpr char value[] = { Chars..., '\0' };
};

template <char... Chars>
constexpr char MyString<Chars...>::value[];

int main()
{
    std::cout << MyString<STR("kernel32.dll")>::value << std::endl;
}

Yet another live demo link

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • no, any static variable or function is not acceptable in my app. can you provide me another way? – Triumphant Aug 30 '14 at 08:22
  • 2
    @Triumphant: Hold on a sec, but you ARE using `std::integral_constant`, what do you think it is? it is a `static` value – Piotr Skotnicki Aug 30 '14 at 08:24
  • Note that you may have some Macro helper to create `MyString<'A', 'B', 'C'>` more friendly (as `MYSTRING("ABC")`), something like in [Aligning static string literals](http://stackoverflow.com/a/22067775/2684539). – Jarod42 Aug 30 '14 at 14:12
  • 1
    @Triumphant: one more update (2), that you may find useful in your project – Piotr Skotnicki Aug 30 '14 at 19:19
2

You may declare a static const char* and use it in std::integral_constant, something like:

static constexpr const char money[] = "money";

int main()
{
    typedef void(*function_t)(int);
    function_t ptrFunc =
        delegate<void, Class, int>
            ::adapter<
                &Class::print,
                std::integral_constant<const char*, money> >::invoke_no_fwd;
    auto type = delegate<void, Class, int>::
        adapter<&Class::print, std::integral_constant<const char*, money>>::invoke_no_fwd;
    ptrFunc(-42); // 0
    type(0); // 42

    return 0;
}

Live example

You may use something like in Aligning static string literals to allow to write the literal string in std::integral_constant with a Macro.

Community
  • 1
  • 1
Jarod42
  • 203,559
  • 14
  • 181
  • 302