Home > Enterprise >  std::disjuction not finding type in parameter pack passed to template function
std::disjuction not finding type in parameter pack passed to template function

Time:03-08

I'm trying to use std::disjuction to test whether a parameter pack contains std::wstring, and nothing I've tried seems to want to make it return the value I'm expecting.

Here's the code as it is currently (https://godbolt.org/z/x99M8avYE):

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

template <typename ...Ts>
using HasWS = std::disjunction<std::is_same<std::wstring,Ts>...>;

template <typename T, typename ...Ts>
using HasWS2 = std::disjunction<std::is_same<T,Ts>...>;

template<typename... Args>
void f(Args&&... args) {
    std::cout << HasWS<Args...>::value << std::endl;
    std::cout << HasWS2<std::wstring, Args...>::value << std::endl;
    std::cout << std::disjunction_v<std::is_same<std::wstring, Args>...> << std::endl;
    (std::cout << typeid(args).name() << std::endl, ...);
}

template <typename T, typename ...Ts>
using areT = std::disjunction<std::is_same<T,Ts>...>;

int main() {
    std::wstring wstr(L"abc");
    std::string str("def");

    static_assert(areT<std::wstring,std::string,std::wstring>::value);    
    static_assert(HasWS<std::wstring,decltype(wstr),decltype(str)>::value);
    static_assert(std::is_same<decltype(wstr), std::wstring>::value);
    
    f(wstr, str);
    f(str, str);
    f(wstr, wstr);

    std::cout << std::is_same_v<decltype(wstr), std::wstring> << std::endl;

    return 0;
}

As you can see, I was experimenting with different ways to call disjuction but none of them would find the wstring and return true. I even stooped as low as printing out the types for each of the elements in the pack and using is_same to make sure that wstr was actually a wstring.

What the heck is going on? Is it something to do with the pack argument to the template that I'm just not aware of?

CodePudding user response:

Note that the parameter type received by f is forwarding reference Args&&, so when you pass in an lvalue wstr, Args will be instantiated as std::wstring& instead of std::wstring, you should remove the reference, e.g.

template<typename... Args>
void f(Args&&... args) {
    std::cout << HasWS<std::remove_reference_t<Args>...>::value << std::endl;
    std::cout << HasWS2<std::wstring, std::remove_reference_t<Args>...>::value << std::endl;
    std::cout << std::disjunction_v<std::is_same<std::wstring, std::remove_reference_t<Args>>...> << std::endl;
}

Demo

  • Related